zklicensing 0.1.0-beta.2 → 0.1.0-beta.21
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/README.md +417 -201
- package/build/agent.d.ts +371 -0
- package/build/agent.d.ts.map +1 -0
- package/build/agent.js +553 -0
- package/build/agent.js.map +1 -0
- package/build/agentActions.d.ts +841 -0
- package/build/agentActions.d.ts.map +1 -0
- package/build/agentActions.js +581 -0
- package/build/agentActions.js.map +1 -0
- package/build/agentRecord.d.ts +83 -0
- package/build/agentRecord.d.ts.map +1 -0
- package/build/agentRecord.js +69 -0
- package/build/agentRecord.js.map +1 -0
- package/build/agentVendor.d.ts +220 -0
- package/build/agentVendor.d.ts.map +1 -0
- package/build/agentVendor.js +306 -0
- package/build/agentVendor.js.map +1 -0
- package/build/appsLookup.d.ts +14 -0
- package/build/appsLookup.d.ts.map +1 -0
- package/build/appsLookup.js +12 -0
- package/build/appsLookup.js.map +1 -0
- package/build/archiveBootstrap.d.ts +31 -5
- package/build/archiveBootstrap.d.ts.map +1 -0
- package/build/archiveBootstrap.js +140 -47
- package/build/archiveBootstrap.js.map +1 -0
- package/build/atomicJson.d.ts +5 -0
- package/build/atomicJson.d.ts.map +1 -0
- package/build/atomicJson.js +55 -0
- package/build/atomicJson.js.map +1 -0
- package/build/bindClient.d.ts +85 -0
- package/build/bindClient.d.ts.map +1 -0
- package/build/bindClient.js +187 -0
- package/build/bindClient.js.map +1 -0
- package/build/buyClient.d.ts +27 -4
- package/build/buyClient.d.ts.map +1 -0
- package/build/buyClient.js +72 -26
- package/build/buyClient.js.map +1 -0
- package/build/chainHead.d.ts +61 -0
- package/build/chainHead.d.ts.map +1 -0
- package/build/chainHead.js +88 -0
- package/build/chainHead.js.map +1 -0
- package/build/compactMerkleMap.d.ts +72 -0
- package/build/compactMerkleMap.d.ts.map +1 -0
- package/build/compactMerkleMap.js +224 -0
- package/build/compactMerkleMap.js.map +1 -0
- package/build/contractInterface.d.ts +191 -51
- package/build/contractInterface.d.ts.map +1 -0
- package/build/contractInterface.js +234 -43
- package/build/contractInterface.js.map +1 -0
- package/build/contractTypes.d.ts +9 -0
- package/build/contractTypes.d.ts.map +1 -0
- package/build/contractTypes.js +28 -0
- package/build/contractTypes.js.map +1 -0
- package/build/countryStats.d.ts +12 -3
- package/build/countryStats.d.ts.map +1 -0
- package/build/countryStats.js +87 -23
- package/build/countryStats.js.map +1 -0
- package/build/deployClient.d.ts +138 -24
- package/build/deployClient.d.ts.map +1 -0
- package/build/deployClient.js +91 -31
- package/build/deployClient.js.map +1 -0
- package/build/deviceIdentity.d.ts +68 -0
- package/build/deviceIdentity.d.ts.map +1 -0
- package/build/deviceIdentity.js +209 -0
- package/build/deviceIdentity.js.map +1 -0
- package/build/freezeClient.d.ts +26 -6
- package/build/freezeClient.d.ts.map +1 -0
- package/build/freezeClient.js +30 -6
- package/build/freezeClient.js.map +1 -0
- package/build/generationClient.d.ts +6 -3
- package/build/generationClient.d.ts.map +1 -0
- package/build/generationClient.js +25 -38
- package/build/generationClient.js.map +1 -0
- package/build/holderSecret.d.ts +70 -0
- package/build/holderSecret.d.ts.map +1 -0
- package/build/holderSecret.js +76 -0
- package/build/holderSecret.js.map +1 -0
- package/build/index.d.ts +38 -38
- package/build/index.d.ts.map +1 -0
- package/build/index.js +97 -121
- package/build/index.js.map +1 -0
- package/build/keysClient.d.ts +142 -0
- package/build/keysClient.d.ts.map +1 -0
- package/build/keysClient.js +109 -0
- package/build/keysClient.js.map +1 -0
- package/build/licenseLeaf.d.ts +76 -0
- package/build/licenseLeaf.d.ts.map +1 -0
- package/build/licenseLeaf.js +189 -0
- package/build/licenseLeaf.js.map +1 -0
- package/build/licenseRecord.d.ts +68 -5
- package/build/licenseRecord.d.ts.map +1 -0
- package/build/licenseRecord.js +26 -1
- package/build/licenseRecord.js.map +1 -0
- package/build/licenseStore.d.ts +81 -4
- package/build/licenseStore.d.ts.map +1 -0
- package/build/licenseStore.js +400 -30
- package/build/licenseStore.js.map +1 -0
- package/build/licenseTrustless.d.ts +43 -0
- package/build/licenseTrustless.d.ts.map +1 -0
- package/build/licenseTrustless.js +180 -0
- package/build/licenseTrustless.js.map +1 -0
- package/build/manifestVerify.d.ts +29 -1
- package/build/manifestVerify.d.ts.map +1 -0
- package/build/manifestVerify.js +46 -4
- package/build/manifestVerify.js.map +1 -0
- package/build/minaPriceHistory.d.ts +9 -0
- package/build/minaPriceHistory.d.ts.map +1 -0
- package/build/minaPriceHistory.js +152 -0
- package/build/minaPriceHistory.js.map +1 -0
- package/build/onChainRoot.d.ts +60 -0
- package/build/onChainRoot.d.ts.map +1 -0
- package/build/onChainRoot.js +74 -0
- package/build/onChainRoot.js.map +1 -0
- package/build/ownershipLicenseHash.d.ts +25 -0
- package/build/ownershipLicenseHash.d.ts.map +1 -0
- package/build/ownershipLicenseHash.js +29 -0
- package/build/ownershipLicenseHash.js.map +1 -0
- package/build/ownershipSignature.d.ts +153 -0
- package/build/ownershipSignature.d.ts.map +1 -0
- package/build/ownershipSignature.js +297 -0
- package/build/ownershipSignature.js.map +1 -0
- package/build/permitCheckFlow.d.ts +155 -0
- package/build/permitCheckFlow.d.ts.map +1 -0
- package/build/permitCheckFlow.js +196 -0
- package/build/permitCheckFlow.js.map +1 -0
- package/build/permitDescribe.d.ts +124 -0
- package/build/permitDescribe.d.ts.map +1 -0
- package/build/permitDescribe.js +324 -0
- package/build/permitDescribe.js.map +1 -0
- package/build/permitInterface.d.ts +85 -0
- package/build/permitInterface.d.ts.map +1 -0
- package/build/permitInterface.js +121 -0
- package/build/permitInterface.js.map +1 -0
- package/build/permitMessages.d.ts +313 -0
- package/build/permitMessages.d.ts.map +1 -0
- package/build/permitMessages.js +462 -0
- package/build/permitMessages.js.map +1 -0
- package/build/permitProof.d.ts +108 -0
- package/build/permitProof.d.ts.map +1 -0
- package/build/permitProof.js +202 -0
- package/build/permitProof.js.map +1 -0
- package/build/permitRegistryRebuild.d.ts +166 -0
- package/build/permitRegistryRebuild.d.ts.map +1 -0
- package/build/permitRegistryRebuild.js +347 -0
- package/build/permitRegistryRebuild.js.map +1 -0
- package/build/permitTree.d.ts +88 -0
- package/build/permitTree.d.ts.map +1 -0
- package/build/permitTree.js +230 -0
- package/build/permitTree.js.map +1 -0
- package/build/permitsClient.d.ts +680 -0
- package/build/permitsClient.d.ts.map +1 -0
- package/build/permitsClient.js +597 -0
- package/build/permitsClient.js.map +1 -0
- package/build/proveErrors.d.ts +50 -0
- package/build/proveErrors.d.ts.map +1 -0
- package/build/proveErrors.js +76 -0
- package/build/proveErrors.js.map +1 -0
- package/build/receipt.d.ts +95 -0
- package/build/receipt.d.ts.map +1 -0
- package/build/receipt.js +84 -0
- package/build/receipt.js.map +1 -0
- package/build/refundClient.d.ts +7 -12
- package/build/refundClient.d.ts.map +1 -0
- package/build/refundClient.js +52 -21
- package/build/refundClient.js.map +1 -0
- package/build/registryTrustVerify.d.ts +78 -0
- package/build/registryTrustVerify.d.ts.map +1 -0
- package/build/registryTrustVerify.js +129 -0
- package/build/registryTrustVerify.js.map +1 -0
- package/build/releaseClient.d.ts +26 -0
- package/build/releaseClient.d.ts.map +1 -0
- package/build/releaseClient.js +65 -0
- package/build/releaseClient.js.map +1 -0
- package/build/renewClient.d.ts +28 -2
- package/build/renewClient.d.ts.map +1 -0
- package/build/renewClient.js +31 -27
- package/build/renewClient.js.map +1 -0
- package/build/seatName.d.ts +8 -0
- package/build/seatName.d.ts.map +1 -0
- package/build/seatName.js +136 -0
- package/build/seatName.js.map +1 -0
- package/build/slotConstants.d.ts +15 -0
- package/build/slotConstants.d.ts.map +1 -0
- package/build/slotConstants.js +17 -0
- package/build/slotConstants.js.map +1 -0
- package/build/statsClient.d.ts +61 -7
- package/build/statsClient.d.ts.map +1 -0
- package/build/statsClient.js +44 -5
- package/build/statsClient.js.map +1 -0
- package/build/successorChain.d.ts +35 -0
- package/build/successorChain.d.ts.map +1 -0
- package/build/successorChain.js +69 -0
- package/build/successorChain.js.map +1 -0
- package/build/taxId.d.ts +44 -0
- package/build/taxId.d.ts.map +1 -0
- package/build/taxId.js +212 -0
- package/build/taxId.js.map +1 -0
- package/build/trustAnchorVerify.d.ts +49 -0
- package/build/trustAnchorVerify.d.ts.map +1 -0
- package/build/trustAnchorVerify.js +432 -0
- package/build/trustAnchorVerify.js.map +1 -0
- package/build/trustAnchorVerifyCli.d.ts +45 -0
- package/build/trustAnchorVerifyCli.d.ts.map +1 -0
- package/build/trustAnchorVerifyCli.js +235 -0
- package/build/trustAnchorVerifyCli.js.map +1 -0
- package/build/txBroadcastClient.d.ts +26 -0
- package/build/txBroadcastClient.d.ts.map +1 -0
- package/build/txBroadcastClient.js +20 -0
- package/build/txBroadcastClient.js.map +1 -0
- package/build/unbindClient.d.ts +77 -0
- package/build/unbindClient.d.ts.map +1 -0
- package/build/unbindClient.js +169 -0
- package/build/unbindClient.js.map +1 -0
- package/build/units.d.ts +28 -0
- package/build/units.d.ts.map +1 -0
- package/build/units.js +65 -0
- package/build/units.js.map +1 -0
- package/build/vatRates.d.ts +54 -0
- package/build/vatRates.d.ts.map +1 -0
- package/build/vatRates.js +82 -0
- package/build/vatRates.js.map +1 -0
- package/build/vatRatesData.d.ts +5 -0
- package/build/vatRatesData.d.ts.map +1 -0
- package/build/vatRatesData.js +42 -0
- package/build/vatRatesData.js.map +1 -0
- package/build/vendorAccountClient.d.ts +66 -0
- package/build/vendorAccountClient.d.ts.map +1 -0
- package/build/vendorAccountClient.js +47 -0
- package/build/vendorAccountClient.js.map +1 -0
- package/build/verifyCore.d.ts +4 -1
- package/build/verifyCore.d.ts.map +1 -0
- package/build/verifyCore.js +21 -10
- package/build/verifyCore.js.map +1 -0
- package/build/verifyOffline.d.ts +85 -0
- package/build/verifyOffline.d.ts.map +1 -0
- package/build/verifyOffline.js +139 -0
- package/build/verifyOffline.js.map +1 -0
- package/build/verifyService.d.ts.map +1 -0
- package/build/verifyService.js +571 -501
- package/build/verifyService.js.map +1 -0
- package/build/verifyWithAncestors.d.ts +19 -0
- package/build/verifyWithAncestors.d.ts.map +1 -0
- package/build/verifyWithAncestors.js +127 -0
- package/build/verifyWithAncestors.js.map +1 -0
- package/build/zipToState.d.ts +2 -0
- package/build/zipToState.d.ts.map +1 -0
- package/build/zipToState.js +94 -0
- package/build/zipToState.js.map +1 -0
- package/package.json +141 -16
- package/src/agent.ts +682 -0
- package/src/agentActions.ts +637 -0
- package/src/agentRecord.ts +121 -0
- package/src/agentVendor.ts +356 -0
- package/src/appsLookup.ts +48 -0
- package/src/archiveBootstrap.ts +386 -0
- package/src/atomicJson.ts +53 -0
- package/src/bindClient.ts +297 -0
- package/src/buyClient.ts +344 -0
- package/src/chainHead.ts +106 -0
- package/src/compactMerkleMap.ts +222 -0
- package/src/contractInterface.ts +465 -0
- package/src/contractTypes.ts +31 -0
- package/src/countryStats.ts +200 -0
- package/src/deployClient.ts +517 -0
- package/src/deviceIdentity.ts +249 -0
- package/src/freezeClient.ts +162 -0
- package/src/generationClient.ts +145 -0
- package/src/holderSecret.ts +91 -0
- package/src/index.ts +362 -0
- package/src/keysClient.ts +135 -0
- package/src/licenseLeaf.ts +221 -0
- package/src/licenseRecord.ts +190 -0
- package/src/licenseStore.ts +767 -0
- package/src/licenseTrustless.ts +207 -0
- package/src/manifestVerify.ts +164 -0
- package/src/minaPriceHistory.ts +166 -0
- package/src/onChainRoot.ts +90 -0
- package/src/ownershipLicenseHash.ts +31 -0
- package/src/ownershipSignature.ts +421 -0
- package/src/permitCheckFlow.ts +227 -0
- package/src/permitDescribe.ts +362 -0
- package/src/permitInterface.ts +146 -0
- package/src/permitMessages.ts +572 -0
- package/src/permitProof.ts +230 -0
- package/src/permitRegistryRebuild.ts +423 -0
- package/src/permitTree.ts +232 -0
- package/src/permitsClient.ts +746 -0
- package/src/proveErrors.ts +98 -0
- package/src/receipt.ts +156 -0
- package/src/refundClient.ts +177 -0
- package/src/registryTrustVerify.ts +192 -0
- package/src/releaseClient.ts +101 -0
- package/src/renewClient.ts +234 -0
- package/src/seatName.ts +165 -0
- package/src/slotConstants.ts +18 -0
- package/src/statsClient.ts +249 -0
- package/src/successorChain.ts +87 -0
- package/src/taxId.ts +227 -0
- package/src/trustAnchorVerify.ts +550 -0
- package/src/trustAnchorVerifyCli.ts +234 -0
- package/src/txBroadcastClient.ts +48 -0
- package/src/unbindClient.ts +233 -0
- package/src/units.ts +74 -0
- package/src/vatRates.ts +100 -0
- package/src/vatRatesData.ts +43 -0
- package/src/vendorAccountClient.ts +120 -0
- package/src/verifyCore.ts +100 -0
- package/src/verifyOffline.ts +212 -0
- package/src/verifyService.ts +982 -0
- package/src/verifyWithAncestors.ts +163 -0
- package/src/zipToState.ts +94 -0
- package/build/licenseProof.d.ts +0 -26
- package/build/licenseProof.js +0 -41
- package/build/migrateClient.d.ts +0 -43
- package/build/migrateClient.js +0 -47
- package/build/ownership.d.ts +0 -34
- package/build/ownership.js +0 -147
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* onChainRoot.ts
|
|
5
|
+
*
|
|
6
|
+
* Non-custodial trust anchor for `verifyOffline`. Reads the live
|
|
7
|
+
* `licensesRoot` (`zkapp.appState[0]`) directly from Mina — no
|
|
8
|
+
* licensing-service round-trip, no trust assumption about whoever
|
|
9
|
+
* served the witness / license record.
|
|
10
|
+
*
|
|
11
|
+
* Pair it with `verifyOffline` to close the trust loop:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { fetchOnChainLicensesRoot } from 'zklicensing/on-chain-root';
|
|
15
|
+
* import { verifyOffline } from 'zklicensing/verify-offline';
|
|
16
|
+
*
|
|
17
|
+
* // 1. Ask the licensing service for a witness + slot snapshot.
|
|
18
|
+
* const snap = await fetch(`${service}/witness?licenseHash=${h}&zkAppAddress=${a}`).then(r => r.json());
|
|
19
|
+
*
|
|
20
|
+
* // 2. Fetch the on-chain root INDEPENDENTLY, from Mina.
|
|
21
|
+
* const onChainRoot = await fetchOnChainLicensesRoot({ zkAppAddress: a, network: 'devnet' });
|
|
22
|
+
*
|
|
23
|
+
* // 3. Cross-check — if they disagree, the service is stale/wrong; bail.
|
|
24
|
+
* if (snap.root !== onChainRoot) throw new Error('service root disagrees with chain');
|
|
25
|
+
*
|
|
26
|
+
* // 4. Fold-verify the snapshot against the on-chain root.
|
|
27
|
+
* const res = verifyOffline({ licensesRoot: onChainRoot, ...snap });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* The read goes to the node's GraphQL API directly: no o1js is needed
|
|
31
|
+
* and o1js's global Mina instance is never touched, so it is safe in
|
|
32
|
+
* long-lived hosts that talk to several networks.
|
|
33
|
+
*/
|
|
34
|
+
// Default read-only public Mina GraphQL endpoints. Devnet points at
|
|
35
|
+
// o1Labs' Mesa cluster (the current stable devnet node published at
|
|
36
|
+
// devnet-plain-1.gcp.o1test.net); mainnet uses Minascan's public node.
|
|
37
|
+
// Neither requires auth or a rate-limit key. Vendors who prefer their
|
|
38
|
+
// own Mina node can override via `graphqlUrl` on the input.
|
|
39
|
+
export const DEFAULT_MINA_GRAPHQL_URLS = {
|
|
40
|
+
mainnet: 'https://api.minascan.io/node/mainnet/v1/graphql',
|
|
41
|
+
devnet: 'https://devnet-plain-1.gcp.o1test.net/graphql',
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Read the live `licensesRoot` from the deployed LicensingApp's
|
|
45
|
+
* on-chain state. Returns the field value as a decimal string,
|
|
46
|
+
* matching the shape `verifyOffline` and the licensing service both
|
|
47
|
+
* consume.
|
|
48
|
+
*
|
|
49
|
+
* Throws on any of:
|
|
50
|
+
* - `fetchAccount` returned an error (network down, wrong endpoint,
|
|
51
|
+
* account doesn't exist on this chain);
|
|
52
|
+
* - account exists but has no zkApp state (not a zkApp address, or
|
|
53
|
+
* contract deployed but `initialize()` never ran).
|
|
54
|
+
*/
|
|
55
|
+
export async function fetchOnChainLicensesRoot(input) {
|
|
56
|
+
const { zkAppAddress } = input;
|
|
57
|
+
const network = input.network ?? 'devnet';
|
|
58
|
+
const graphqlUrl = input.graphqlUrl ?? DEFAULT_MINA_GRAPHQL_URLS[network];
|
|
59
|
+
// Over the node's GraphQL API: no o1js, no global Mina instance.
|
|
60
|
+
const { readZkappAccount } = await import('./chainHead.js');
|
|
61
|
+
let account;
|
|
62
|
+
try {
|
|
63
|
+
account = await readZkappAccount({ address: zkAppAddress, graphqlUrl });
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
throw new Error(`fetchAccount(${zkAppAddress}) via ${graphqlUrl} failed: ${e?.message ?? e}`);
|
|
67
|
+
}
|
|
68
|
+
const root = account.found ? account.appState?.[0] : undefined;
|
|
69
|
+
if (!root) {
|
|
70
|
+
throw new Error(`zkApp ${zkAppAddress} has no appState — is the LicensingApp deployed and initialized on ${network}?`);
|
|
71
|
+
}
|
|
72
|
+
return root;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=onChainRoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onChainRoot.js","sourceRoot":"","sources":["../src/onChainRoot.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,oCAAoC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,oEAAoE;AACpE,oEAAoE;AACpE,uEAAuE;AACvE,sEAAsE;AACtE,4DAA4D;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,iDAAiD;IAC1D,MAAM,EAAG,+CAA+C;CAChD,CAAC;AAYX;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAoC;IAEpC,MAAM,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAC/B,MAAM,OAAO,GAAgB,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC;IACvD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAE1E,iEAAiE;IACjE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC5D,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,gBAAgB,YAAY,SAAS,UAAU,YAAY,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,SAAS,YAAY,sEAAsE,OAAO,GAAG,CACtG,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ownershipLicenseHash.ts
|
|
3
|
+
*
|
|
4
|
+
* Field-side binding between the buyer's Pallas Schnorr pubkey and the
|
|
5
|
+
* `licenseHash` Field stored on-chain. The buy circuit and the buy client
|
|
6
|
+
* both compute this from the pubkey and assert equality — that mutual
|
|
7
|
+
* assertion is what proves knowledge of the passphrase without ever
|
|
8
|
+
* showing the passphrase to the network.
|
|
9
|
+
*
|
|
10
|
+
* A Pallas `PublicKey` is `(x: Field, isOdd: Bool)` — the two Fields that
|
|
11
|
+
* uniquely identify the compressed point. Poseidon-hashing them yields a
|
|
12
|
+
* single Field that matches the on-chain shape of every other `licenseHash`
|
|
13
|
+
* used by LicensingApp (which treats licenseHash as an opaque Field
|
|
14
|
+
* commitment, not a specific preimage).
|
|
15
|
+
*/
|
|
16
|
+
import { PublicKey } from 'o1js';
|
|
17
|
+
/**
|
|
18
|
+
* Derive the Field-side `licenseHash` from a Pallas Schnorr pubkey. The
|
|
19
|
+
* hash is domain-free because the whole platform treats `licenseHash` as
|
|
20
|
+
* an opaque commitment — the on-chain contract never re-derives it from
|
|
21
|
+
* a preimage, so there's no cross-preimage collision surface to guard
|
|
22
|
+
* against here.
|
|
23
|
+
*/
|
|
24
|
+
export declare function licenseHashFromPubkey(publicKey: PublicKey): string;
|
|
25
|
+
//# sourceMappingURL=ownershipLicenseHash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownershipLicenseHash.d.ts","sourceRoot":"","sources":["../src/ownershipLicenseHash.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAY,SAAS,EAAE,MAAM,MAAM,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAElE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* ownershipLicenseHash.ts
|
|
5
|
+
*
|
|
6
|
+
* Field-side binding between the buyer's Pallas Schnorr pubkey and the
|
|
7
|
+
* `licenseHash` Field stored on-chain. The buy circuit and the buy client
|
|
8
|
+
* both compute this from the pubkey and assert equality — that mutual
|
|
9
|
+
* assertion is what proves knowledge of the passphrase without ever
|
|
10
|
+
* showing the passphrase to the network.
|
|
11
|
+
*
|
|
12
|
+
* A Pallas `PublicKey` is `(x: Field, isOdd: Bool)` — the two Fields that
|
|
13
|
+
* uniquely identify the compressed point. Poseidon-hashing them yields a
|
|
14
|
+
* single Field that matches the on-chain shape of every other `licenseHash`
|
|
15
|
+
* used by LicensingApp (which treats licenseHash as an opaque Field
|
|
16
|
+
* commitment, not a specific preimage).
|
|
17
|
+
*/
|
|
18
|
+
import { Poseidon } from 'o1js';
|
|
19
|
+
/**
|
|
20
|
+
* Derive the Field-side `licenseHash` from a Pallas Schnorr pubkey. The
|
|
21
|
+
* hash is domain-free because the whole platform treats `licenseHash` as
|
|
22
|
+
* an opaque commitment — the on-chain contract never re-derives it from
|
|
23
|
+
* a preimage, so there's no cross-preimage collision surface to guard
|
|
24
|
+
* against here.
|
|
25
|
+
*/
|
|
26
|
+
export function licenseHashFromPubkey(publicKey) {
|
|
27
|
+
return Poseidon.hash([publicKey.x, publicKey.isOdd.toField()]).toString();
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ownershipLicenseHash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownershipLicenseHash.js","sourceRoot":"","sources":["../src/ownershipLicenseHash.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,oCAAoC;AAEpC;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAa,MAAM,MAAM,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAoB;IACxD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ownershipSignature.ts
|
|
3
|
+
*
|
|
4
|
+
* Schnorr-over-Pallas signing primitive for the two on-chain flows that
|
|
5
|
+
* need the passphrase-derived owner key:
|
|
6
|
+
*
|
|
7
|
+
* 1. The /prove/bind and /prove/unbind flows — the passphrase-derived
|
|
8
|
+
* keypair authorizes device slot mutations, and the signature is
|
|
9
|
+
* re-verified INSIDE the circuit by `Signature.verify()` so even a
|
|
10
|
+
* compromised licensing service cannot forge a bind.
|
|
11
|
+
* 2. The retained `ActivationMessage` shape (see below) — kept so external
|
|
12
|
+
* tooling can still sign an "I hold the passphrase for this license"
|
|
13
|
+
* assertion off-band. The platform no longer runs a challenge/respond
|
|
14
|
+
* endpoint; the shape is purely an SDK primitive now.
|
|
15
|
+
*
|
|
16
|
+
* Deterministic HKDF-SHA256 derivation of a seed from the passphrase,
|
|
17
|
+
* reduced to a Pallas scalar → o1js `PrivateKey`. The buyer can
|
|
18
|
+
* re-derive the same keypair anywhere from just the passphrase.
|
|
19
|
+
*
|
|
20
|
+
* o1js-dependent by design: the whole point of switching from Ed25519 to
|
|
21
|
+
* Pallas Schnorr is native in-circuit verification. Any client that
|
|
22
|
+
* signs an activation or binding challenge already ships o1js for the
|
|
23
|
+
* downstream buy/verify surface, so the "keep this module o1js-free"
|
|
24
|
+
* constraint that motivated the Ed25519 version no longer applies.
|
|
25
|
+
*
|
|
26
|
+
* HKDF still needs WebCrypto (Node ≥ 20, Chromium 137+, Safari 17+,
|
|
27
|
+
* Firefox 130+). The module throws at derive time if
|
|
28
|
+
* `globalThis.crypto.subtle` is unavailable — callers cannot silently
|
|
29
|
+
* fall back to a weaker path.
|
|
30
|
+
*/
|
|
31
|
+
import { Field, PrivateKey, PublicKey, Signature } from 'o1js';
|
|
32
|
+
export declare const TAG_ACTIVATION = 1n;
|
|
33
|
+
export declare const TAG_BINDING = 2n;
|
|
34
|
+
export declare const TAG_UNBINDING = 3n;
|
|
35
|
+
/**
|
|
36
|
+
* HKDF-SHA256 with empty salt and a per-app domain-separation info
|
|
37
|
+
* string (`zkLicensing/v1/ownership|<zkAppAddress>`). Deterministic:
|
|
38
|
+
* same (passphrase, zkAppAddress) → same 32-byte seed. Different
|
|
39
|
+
* zkAppAddress → cryptographically unrelated seed even with the same
|
|
40
|
+
* passphrase.
|
|
41
|
+
*/
|
|
42
|
+
export declare function deriveSeed(passphrase: string, zkAppAddress: string): Promise<Uint8Array>;
|
|
43
|
+
export type OwnershipKeypair = {
|
|
44
|
+
privateKey: PrivateKey;
|
|
45
|
+
publicKey: PublicKey;
|
|
46
|
+
publicKeyBase58: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Derive a Pallas Schnorr keypair deterministically from (passphrase,
|
|
50
|
+
* zkAppAddress). The keypair is bound to the specific app: the same
|
|
51
|
+
* passphrase used against a different app yields a different keypair,
|
|
52
|
+
* so a leaked passphrase cannot be replayed as an activation for any
|
|
53
|
+
* other app.
|
|
54
|
+
*
|
|
55
|
+
* The 32-byte HKDF output is interpreted as a big-endian integer and
|
|
56
|
+
* passed to `PrivateKey.fromBigInt`, which reduces it modulo the Pallas
|
|
57
|
+
* scalar field order internally. All 2^256 possible HKDF outputs map to
|
|
58
|
+
* valid private keys with (256 - log2(Fq_order))-bit modular bias — the
|
|
59
|
+
* scalar field is ~254 bits, so bias is <2^-253 and lies well below any
|
|
60
|
+
* practical distinguisher.
|
|
61
|
+
*/
|
|
62
|
+
export declare function deriveOwnershipKeypair(passphrase: string, zkAppAddress: string): Promise<OwnershipKeypair>;
|
|
63
|
+
/**
|
|
64
|
+
* The ownership keypair of license `licenseHash`, trying each candidate app
|
|
65
|
+
* address in turn. The key is derived from the address the license was
|
|
66
|
+
* issued on; after a redeploy the license carries over to the successor
|
|
67
|
+
* unchanged, so its key is the earlier generation's. Pass the app's
|
|
68
|
+
* generation addresses (any order; the live one first is cheapest for new
|
|
69
|
+
* licenses). A wrong address only gives a key that doesn't match, so the
|
|
70
|
+
* list needn't be authenticated. Null when none matches (another passphrase).
|
|
71
|
+
*/
|
|
72
|
+
export declare function findOwnershipKeypair(passphrase: string, licenseHash: string, candidateAddresses: readonly string[]): Promise<(OwnershipKeypair & {
|
|
73
|
+
zkAppAddress: string;
|
|
74
|
+
}) | null>;
|
|
75
|
+
/**
|
|
76
|
+
* The addresses of every generation of the app at `zkAppAddress` (any of
|
|
77
|
+
* them), live first, from the keeper's generation list; just
|
|
78
|
+
* `zkAppAddress` when the keeper doesn't know it. For findOwnershipKeypair.
|
|
79
|
+
*/
|
|
80
|
+
export declare function ownershipCandidateAddresses(keeperUrl: string, zkAppAddress: string, fetcher?: typeof fetch): Promise<string[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Activation assertion shape. Proves the caller holds the passphrase
|
|
83
|
+
* that derived the license's ownerPubKey. Retained as an SDK primitive
|
|
84
|
+
* so external tooling can still request / verify an off-band "I own
|
|
85
|
+
* this license" signature — the on-chain flows themselves do not use
|
|
86
|
+
* it.
|
|
87
|
+
*/
|
|
88
|
+
export type ActivationMessage = {
|
|
89
|
+
licenseHash: string;
|
|
90
|
+
nonce: string;
|
|
91
|
+
zkAppAddress: string;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Binding / unbinding message — the /prove/bind and /prove/unbind
|
|
95
|
+
* flows. Authorizes a specific device commitment being placed into or
|
|
96
|
+
* cleared from a specific slot on a specific license.
|
|
97
|
+
*/
|
|
98
|
+
export type BindingMessage = {
|
|
99
|
+
licenseHash: string;
|
|
100
|
+
deviceCommitment: string;
|
|
101
|
+
slotIndex: number;
|
|
102
|
+
nonce: string;
|
|
103
|
+
slotState: string;
|
|
104
|
+
expirySlot: number;
|
|
105
|
+
zkAppAddress: string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Packed (boundAt, freedAt) of one slot as the circuit sees it — the
|
|
109
|
+
* `slotState` a BindingMessage must commit to. Takes the slot entry from a
|
|
110
|
+
* LicenseRecord's `devices[]` (as served by GET /license/:zkApp/:hash);
|
|
111
|
+
* an absent entry is a pristine slot (0).
|
|
112
|
+
*/
|
|
113
|
+
export declare function slotStateOf(device?: {
|
|
114
|
+
boundAtSlot: number;
|
|
115
|
+
freedAtSlot: number;
|
|
116
|
+
} | null): string;
|
|
117
|
+
export type ChallengeMessage = ActivationMessage;
|
|
118
|
+
/**
|
|
119
|
+
* Canonicalize the activation message into the Field[] that
|
|
120
|
+
* `Signature.create` / `Signature.verify` hash. The domain-separation
|
|
121
|
+
* tag prefix means no captured activation signature can be replayed as
|
|
122
|
+
* a binding signature, even if all other fields collide.
|
|
123
|
+
*/
|
|
124
|
+
export declare function activationMessageFields(msg: ActivationMessage): Field[];
|
|
125
|
+
export declare function bindingMessageFields(msg: BindingMessage): Field[];
|
|
126
|
+
export declare function unbindingMessageFields(msg: BindingMessage): Field[];
|
|
127
|
+
export declare function signActivation(privateKey: PrivateKey, msg: ActivationMessage): Signature;
|
|
128
|
+
export declare function signBinding(privateKey: PrivateKey, msg: BindingMessage): Signature;
|
|
129
|
+
export declare function signUnbinding(privateKey: PrivateKey, msg: BindingMessage): Signature;
|
|
130
|
+
export declare function signChallenge(privateKey: PrivateKey, msg: ChallengeMessage): Signature;
|
|
131
|
+
/**
|
|
132
|
+
* Verify an activation signature. Returns false (never throws) for any
|
|
133
|
+
* failure — malformed pubkey, malformed signature, actual signature
|
|
134
|
+
* mismatch. Callers get a single go/no-go decision without having to
|
|
135
|
+
* distinguish "invalid" from "unparseable."
|
|
136
|
+
*/
|
|
137
|
+
export declare function verifyActivation(publicKey: PublicKey, msg: ActivationMessage, signature: Signature): boolean;
|
|
138
|
+
export declare function verifyBinding(publicKey: PublicKey, msg: BindingMessage, signature: Signature): boolean;
|
|
139
|
+
export declare function verifyUnbinding(publicKey: PublicKey, msg: BindingMessage, signature: Signature): boolean;
|
|
140
|
+
export declare function verifyChallenge(publicKey: PublicKey, msg: ChallengeMessage, signature: Signature): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Encode a signature for the wire (POST body, ProofFile JSON, etc).
|
|
143
|
+
* Base58 matches Mina's canonical serialization for both PublicKey and
|
|
144
|
+
* Signature, keeping the same encoding shape across everything the
|
|
145
|
+
* buyer's SDK produces.
|
|
146
|
+
*/
|
|
147
|
+
export declare function encodeSignature(sig: Signature): string;
|
|
148
|
+
export declare function decodeSignature(base58: string): Signature;
|
|
149
|
+
export declare function encodePublicKey(pk: PublicKey): string;
|
|
150
|
+
export declare function decodePublicKey(base58: string): PublicKey;
|
|
151
|
+
export declare function encodeBase64(bytes: Uint8Array): string;
|
|
152
|
+
export declare function decodeBase64(b64: string): Uint8Array;
|
|
153
|
+
//# sourceMappingURL=ownershipSignature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownershipSignature.d.ts","sourceRoot":"","sources":["../src/ownershipSignature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 zkLicensing project developers
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
/**
|
|
4
|
+
* ownershipSignature.ts
|
|
5
|
+
*
|
|
6
|
+
* Schnorr-over-Pallas signing primitive for the two on-chain flows that
|
|
7
|
+
* need the passphrase-derived owner key:
|
|
8
|
+
*
|
|
9
|
+
* 1. The /prove/bind and /prove/unbind flows — the passphrase-derived
|
|
10
|
+
* keypair authorizes device slot mutations, and the signature is
|
|
11
|
+
* re-verified INSIDE the circuit by `Signature.verify()` so even a
|
|
12
|
+
* compromised licensing service cannot forge a bind.
|
|
13
|
+
* 2. The retained `ActivationMessage` shape (see below) — kept so external
|
|
14
|
+
* tooling can still sign an "I hold the passphrase for this license"
|
|
15
|
+
* assertion off-band. The platform no longer runs a challenge/respond
|
|
16
|
+
* endpoint; the shape is purely an SDK primitive now.
|
|
17
|
+
*
|
|
18
|
+
* Deterministic HKDF-SHA256 derivation of a seed from the passphrase,
|
|
19
|
+
* reduced to a Pallas scalar → o1js `PrivateKey`. The buyer can
|
|
20
|
+
* re-derive the same keypair anywhere from just the passphrase.
|
|
21
|
+
*
|
|
22
|
+
* o1js-dependent by design: the whole point of switching from Ed25519 to
|
|
23
|
+
* Pallas Schnorr is native in-circuit verification. Any client that
|
|
24
|
+
* signs an activation or binding challenge already ships o1js for the
|
|
25
|
+
* downstream buy/verify surface, so the "keep this module o1js-free"
|
|
26
|
+
* constraint that motivated the Ed25519 version no longer applies.
|
|
27
|
+
*
|
|
28
|
+
* HKDF still needs WebCrypto (Node ≥ 20, Chromium 137+, Safari 17+,
|
|
29
|
+
* Firefox 130+). The module throws at derive time if
|
|
30
|
+
* `globalThis.crypto.subtle` is unavailable — callers cannot silently
|
|
31
|
+
* fall back to a weaker path.
|
|
32
|
+
*/
|
|
33
|
+
import { Field, PrivateKey, PublicKey, Signature, UInt32 } from 'o1js';
|
|
34
|
+
import { packSlotTimes } from './licenseLeaf.js';
|
|
35
|
+
import { licenseHashFromPubkey } from './ownershipLicenseHash.js';
|
|
36
|
+
// HKDF info binds the derivation to a specific zkApp address, so the
|
|
37
|
+
// same passphrase yields different keypairs for different apps. This
|
|
38
|
+
// makes credentials per-app: a leaked passphrase for app A cannot be
|
|
39
|
+
// replayed as an activation for app B. RFC 5869 designates `info` as
|
|
40
|
+
// the domain-separation channel (salt is for randomness, which we don't
|
|
41
|
+
// have here — the passphrase IS the secret input).
|
|
42
|
+
//
|
|
43
|
+
// The `v1` prefix reserves room to rotate the KDF or the target key type
|
|
44
|
+
// later without a silent collision — a future scheme bumps to `v2` and
|
|
45
|
+
// derives an unrelated key from the same passphrase.
|
|
46
|
+
const HKDF_INFO_PREFIX = 'zkLicensing/v1/ownership|';
|
|
47
|
+
const HKDF_SALT = new Uint8Array(0);
|
|
48
|
+
// Domain-separation tags baked into every signed message. Prevents a
|
|
49
|
+
// signature captured on one flow (activation) from being replayed on
|
|
50
|
+
// another (binding) — the first Field the signer hashes is the flow ID,
|
|
51
|
+
// so the two signatures live in disjoint spaces even at identical
|
|
52
|
+
// (licenseHash, nonce).
|
|
53
|
+
//
|
|
54
|
+
// Exported so `LicensingApp.bind()` / `unbind()` can rebuild the exact
|
|
55
|
+
// same Field[] preimage inside the circuit for `Signature.verify()`.
|
|
56
|
+
// Bumping these values is a hardfork — every off-chain signer and every
|
|
57
|
+
// deployed circuit would need to agree.
|
|
58
|
+
export const TAG_ACTIVATION = 1n;
|
|
59
|
+
export const TAG_BINDING = 2n;
|
|
60
|
+
export const TAG_UNBINDING = 3n;
|
|
61
|
+
function buildHkdfInfo(zkAppAddress) {
|
|
62
|
+
return new TextEncoder().encode(HKDF_INFO_PREFIX + zkAppAddress);
|
|
63
|
+
}
|
|
64
|
+
function utf8Bytes(s) {
|
|
65
|
+
return new TextEncoder().encode(s);
|
|
66
|
+
}
|
|
67
|
+
function bytesToBase64(bytes) {
|
|
68
|
+
let s = '';
|
|
69
|
+
for (const b of bytes)
|
|
70
|
+
s += String.fromCharCode(b);
|
|
71
|
+
return btoa(s);
|
|
72
|
+
}
|
|
73
|
+
function base64ToBytes(b64) {
|
|
74
|
+
const bin = atob(b64);
|
|
75
|
+
const out = new Uint8Array(bin.length);
|
|
76
|
+
for (let i = 0; i < bin.length; i++)
|
|
77
|
+
out[i] = bin.charCodeAt(i);
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
function subtle() {
|
|
81
|
+
const s = globalThis.crypto?.subtle;
|
|
82
|
+
if (!s) {
|
|
83
|
+
throw new Error('WebCrypto unavailable — ownershipSignature requires Node ≥ 20 or a modern browser (Chromium 137+, Safari 17+, Firefox 130+).');
|
|
84
|
+
}
|
|
85
|
+
return s;
|
|
86
|
+
}
|
|
87
|
+
function bytesToBigInt(bytes) {
|
|
88
|
+
let n = 0n;
|
|
89
|
+
for (const b of bytes)
|
|
90
|
+
n = (n << 8n) | BigInt(b);
|
|
91
|
+
return n;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* HKDF-SHA256 with empty salt and a per-app domain-separation info
|
|
95
|
+
* string (`zkLicensing/v1/ownership|<zkAppAddress>`). Deterministic:
|
|
96
|
+
* same (passphrase, zkAppAddress) → same 32-byte seed. Different
|
|
97
|
+
* zkAppAddress → cryptographically unrelated seed even with the same
|
|
98
|
+
* passphrase.
|
|
99
|
+
*/
|
|
100
|
+
export async function deriveSeed(passphrase, zkAppAddress) {
|
|
101
|
+
const baseKey = await subtle().importKey('raw', utf8Bytes(passphrase), 'HKDF', false, ['deriveBits']);
|
|
102
|
+
const info = buildHkdfInfo(zkAppAddress);
|
|
103
|
+
const bits = await subtle().deriveBits({
|
|
104
|
+
name: 'HKDF',
|
|
105
|
+
hash: 'SHA-256',
|
|
106
|
+
salt: HKDF_SALT,
|
|
107
|
+
info: info,
|
|
108
|
+
}, baseKey, 256);
|
|
109
|
+
return new Uint8Array(bits);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Derive a Pallas Schnorr keypair deterministically from (passphrase,
|
|
113
|
+
* zkAppAddress). The keypair is bound to the specific app: the same
|
|
114
|
+
* passphrase used against a different app yields a different keypair,
|
|
115
|
+
* so a leaked passphrase cannot be replayed as an activation for any
|
|
116
|
+
* other app.
|
|
117
|
+
*
|
|
118
|
+
* The 32-byte HKDF output is interpreted as a big-endian integer and
|
|
119
|
+
* passed to `PrivateKey.fromBigInt`, which reduces it modulo the Pallas
|
|
120
|
+
* scalar field order internally. All 2^256 possible HKDF outputs map to
|
|
121
|
+
* valid private keys with (256 - log2(Fq_order))-bit modular bias — the
|
|
122
|
+
* scalar field is ~254 bits, so bias is <2^-253 and lies well below any
|
|
123
|
+
* practical distinguisher.
|
|
124
|
+
*/
|
|
125
|
+
export async function deriveOwnershipKeypair(passphrase, zkAppAddress) {
|
|
126
|
+
const seed = await deriveSeed(passphrase, zkAppAddress);
|
|
127
|
+
const privateKey = PrivateKey.fromBigInt(bytesToBigInt(seed));
|
|
128
|
+
const publicKey = privateKey.toPublicKey();
|
|
129
|
+
return { privateKey, publicKey, publicKeyBase58: publicKey.toBase58() };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The ownership keypair of license `licenseHash`, trying each candidate app
|
|
133
|
+
* address in turn. The key is derived from the address the license was
|
|
134
|
+
* issued on; after a redeploy the license carries over to the successor
|
|
135
|
+
* unchanged, so its key is the earlier generation's. Pass the app's
|
|
136
|
+
* generation addresses (any order; the live one first is cheapest for new
|
|
137
|
+
* licenses). A wrong address only gives a key that doesn't match, so the
|
|
138
|
+
* list needn't be authenticated. Null when none matches (another passphrase).
|
|
139
|
+
*/
|
|
140
|
+
export async function findOwnershipKeypair(passphrase, licenseHash, candidateAddresses) {
|
|
141
|
+
for (const zkAppAddress of [...new Set(candidateAddresses)]) {
|
|
142
|
+
const kp = await deriveOwnershipKeypair(passphrase, zkAppAddress);
|
|
143
|
+
if (licenseHashFromPubkey(kp.publicKey) === licenseHash)
|
|
144
|
+
return { ...kp, zkAppAddress };
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The addresses of every generation of the app at `zkAppAddress` (any of
|
|
150
|
+
* them), live first, from the keeper's generation list; just
|
|
151
|
+
* `zkAppAddress` when the keeper doesn't know it. For findOwnershipKeypair.
|
|
152
|
+
*/
|
|
153
|
+
export async function ownershipCandidateAddresses(keeperUrl, zkAppAddress, fetcher = fetch) {
|
|
154
|
+
try {
|
|
155
|
+
const r = await fetcher(`${keeperUrl.replace(/\/+$/, '')}/apps/by-address/${encodeURIComponent(zkAppAddress)}`);
|
|
156
|
+
if (!r.ok)
|
|
157
|
+
return [zkAppAddress];
|
|
158
|
+
const body = await r.json();
|
|
159
|
+
const gens = Array.isArray(body.generations) ? [...body.generations].sort((a, b) => b.gen - a.gen).map(g => g.zkAppAddress) : [];
|
|
160
|
+
return [...new Set([zkAppAddress, ...gens])];
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return [zkAppAddress];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Packed (boundAt, freedAt) of one slot as the circuit sees it — the
|
|
168
|
+
* `slotState` a BindingMessage must commit to. Takes the slot entry from a
|
|
169
|
+
* LicenseRecord's `devices[]` (as served by GET /license/:zkApp/:hash);
|
|
170
|
+
* an absent entry is a pristine slot (0).
|
|
171
|
+
*/
|
|
172
|
+
export function slotStateOf(device) {
|
|
173
|
+
if (!device)
|
|
174
|
+
return '0';
|
|
175
|
+
return packSlotTimes(UInt32.from(device.boundAtSlot), UInt32.from(device.freedAtSlot)).toString();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Canonicalize the activation message into the Field[] that
|
|
179
|
+
* `Signature.create` / `Signature.verify` hash. The domain-separation
|
|
180
|
+
* tag prefix means no captured activation signature can be replayed as
|
|
181
|
+
* a binding signature, even if all other fields collide.
|
|
182
|
+
*/
|
|
183
|
+
export function activationMessageFields(msg) {
|
|
184
|
+
const addr = PublicKey.fromBase58(msg.zkAppAddress);
|
|
185
|
+
return [
|
|
186
|
+
Field(TAG_ACTIVATION),
|
|
187
|
+
Field(msg.licenseHash),
|
|
188
|
+
Field(msg.nonce),
|
|
189
|
+
addr.x,
|
|
190
|
+
addr.isOdd.toField(),
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Canonicalize a binding or unbinding message. The `tag` argument
|
|
195
|
+
* distinguishes bind (TAG_BINDING) from unbind (TAG_UNBINDING) so a
|
|
196
|
+
* bind signature captured off-chain cannot be replayed as an unbind
|
|
197
|
+
* even at identical (licenseHash, deviceCommitment, slotIndex, nonce).
|
|
198
|
+
*/
|
|
199
|
+
function bindingLikeFields(tag, msg) {
|
|
200
|
+
const addr = PublicKey.fromBase58(msg.zkAppAddress);
|
|
201
|
+
return [
|
|
202
|
+
Field(tag),
|
|
203
|
+
Field(msg.licenseHash),
|
|
204
|
+
Field(msg.deviceCommitment),
|
|
205
|
+
Field(msg.slotIndex),
|
|
206
|
+
Field(msg.nonce),
|
|
207
|
+
Field(msg.slotState),
|
|
208
|
+
Field(msg.expirySlot),
|
|
209
|
+
addr.x,
|
|
210
|
+
addr.isOdd.toField(),
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
export function bindingMessageFields(msg) {
|
|
214
|
+
return bindingLikeFields(TAG_BINDING, msg);
|
|
215
|
+
}
|
|
216
|
+
export function unbindingMessageFields(msg) {
|
|
217
|
+
return bindingLikeFields(TAG_UNBINDING, msg);
|
|
218
|
+
}
|
|
219
|
+
// ── Signing ───────────────────────────────────────────────────────
|
|
220
|
+
export function signActivation(privateKey, msg) {
|
|
221
|
+
return Signature.create(privateKey, activationMessageFields(msg));
|
|
222
|
+
}
|
|
223
|
+
export function signBinding(privateKey, msg) {
|
|
224
|
+
return Signature.create(privateKey, bindingMessageFields(msg));
|
|
225
|
+
}
|
|
226
|
+
export function signUnbinding(privateKey, msg) {
|
|
227
|
+
return Signature.create(privateKey, unbindingMessageFields(msg));
|
|
228
|
+
}
|
|
229
|
+
// Retained for back-compat with the Ed25519-era name. New code should
|
|
230
|
+
// call signActivation directly.
|
|
231
|
+
export function signChallenge(privateKey, msg) {
|
|
232
|
+
return signActivation(privateKey, msg);
|
|
233
|
+
}
|
|
234
|
+
// ── Verification ──────────────────────────────────────────────────
|
|
235
|
+
/**
|
|
236
|
+
* Verify an activation signature. Returns false (never throws) for any
|
|
237
|
+
* failure — malformed pubkey, malformed signature, actual signature
|
|
238
|
+
* mismatch. Callers get a single go/no-go decision without having to
|
|
239
|
+
* distinguish "invalid" from "unparseable."
|
|
240
|
+
*/
|
|
241
|
+
export function verifyActivation(publicKey, msg, signature) {
|
|
242
|
+
try {
|
|
243
|
+
return signature.verify(publicKey, activationMessageFields(msg)).toBoolean();
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
export function verifyBinding(publicKey, msg, signature) {
|
|
250
|
+
try {
|
|
251
|
+
return signature.verify(publicKey, bindingMessageFields(msg)).toBoolean();
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
export function verifyUnbinding(publicKey, msg, signature) {
|
|
258
|
+
try {
|
|
259
|
+
return signature.verify(publicKey, unbindingMessageFields(msg)).toBoolean();
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Back-compat alias, see signChallenge.
|
|
266
|
+
export function verifyChallenge(publicKey, msg, signature) {
|
|
267
|
+
return verifyActivation(publicKey, msg, signature);
|
|
268
|
+
}
|
|
269
|
+
// ── Wire encoding helpers ─────────────────────────────────────────
|
|
270
|
+
/**
|
|
271
|
+
* Encode a signature for the wire (POST body, ProofFile JSON, etc).
|
|
272
|
+
* Base58 matches Mina's canonical serialization for both PublicKey and
|
|
273
|
+
* Signature, keeping the same encoding shape across everything the
|
|
274
|
+
* buyer's SDK produces.
|
|
275
|
+
*/
|
|
276
|
+
export function encodeSignature(sig) {
|
|
277
|
+
return sig.toBase58();
|
|
278
|
+
}
|
|
279
|
+
export function decodeSignature(base58) {
|
|
280
|
+
return Signature.fromBase58(base58);
|
|
281
|
+
}
|
|
282
|
+
export function encodePublicKey(pk) {
|
|
283
|
+
return pk.toBase58();
|
|
284
|
+
}
|
|
285
|
+
export function decodePublicKey(base58) {
|
|
286
|
+
return PublicKey.fromBase58(base58);
|
|
287
|
+
}
|
|
288
|
+
// Retained so callers that already do `encodeBase64(seed)` for logging
|
|
289
|
+
// or persistence keep working — this module no longer produces raw byte
|
|
290
|
+
// pubkeys or signatures, only o1js objects with .toBase58().
|
|
291
|
+
export function encodeBase64(bytes) {
|
|
292
|
+
return bytesToBase64(bytes);
|
|
293
|
+
}
|
|
294
|
+
export function decodeBase64(b64) {
|
|
295
|
+
return base64ToBytes(b64);
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=ownershipSignature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownershipSignature.js","sourceRoot":"","sources":["../src/ownershipSignature.ts"],"names":[],"mappings":"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"}
|