@degenerate/sharedata 0.2.7 → 0.4.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/README.md +31 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/manager/share-data-manager-events.d.ts +27 -0
- package/dist/manager/share-data-manager-events.d.ts.map +1 -0
- package/dist/manager/share-data-manager-events.js +2 -0
- package/dist/manager/share-data-manager.d.ts +84 -0
- package/dist/manager/share-data-manager.d.ts.map +1 -0
- package/dist/manager/share-data-manager.js +210 -0
- package/dist/persistence/block-factory-registry.d.ts +57 -0
- package/dist/persistence/block-factory-registry.d.ts.map +1 -0
- package/dist/persistence/block-factory-registry.js +36 -0
- package/dist/persistence/deserialize-share-data.d.ts +18 -0
- package/dist/persistence/deserialize-share-data.d.ts.map +1 -0
- package/dist/persistence/deserialize-share-data.js +149 -0
- package/dist/persistence/file-share-data-repository.d.ts +30 -0
- package/dist/persistence/file-share-data-repository.d.ts.map +1 -0
- package/dist/persistence/file-share-data-repository.js +147 -0
- package/dist/persistence/firestore-share-data-repository.d.ts +38 -0
- package/dist/persistence/firestore-share-data-repository.d.ts.map +1 -0
- package/dist/persistence/firestore-share-data-repository.js +78 -0
- package/dist/persistence/in-memory-share-data-repository.d.ts +19 -0
- package/dist/persistence/in-memory-share-data-repository.d.ts.map +1 -0
- package/dist/persistence/in-memory-share-data-repository.js +48 -0
- package/dist/persistence/serialize-share-data.d.ts +22 -0
- package/dist/persistence/serialize-share-data.d.ts.map +1 -0
- package/dist/persistence/serialize-share-data.js +66 -0
- package/dist/persistence/share-data-repository.d.ts +49 -0
- package/dist/persistence/share-data-repository.d.ts.map +1 -0
- package/dist/persistence/share-data-repository.js +2 -0
- package/dist/share-data/creation/create-share-data-initial-crypto.d.ts +11 -0
- package/dist/share-data/creation/create-share-data-initial-crypto.d.ts.map +1 -0
- package/dist/share-data/creation/create-share-data-initial-crypto.js +26 -0
- package/dist/share-data/helpers/calculate-share-data-string.d.ts +21 -0
- package/dist/share-data/helpers/calculate-share-data-string.d.ts.map +1 -0
- package/dist/share-data/helpers/calculate-share-data-string.js +71 -0
- package/dist/share-data/helpers/config/default-share-data-string.config.d.ts +7 -0
- package/dist/share-data/helpers/config/default-share-data-string.config.d.ts.map +1 -0
- package/dist/share-data/helpers/config/default-share-data-string.config.js +30 -0
- package/dist/share-data/helpers/config/stringify.d.ts +5 -0
- package/dist/share-data/helpers/config/stringify.d.ts.map +1 -0
- package/dist/share-data/helpers/config/stringify.js +10 -0
- package/dist/share-data/helpers/get-array-string.d.ts +6 -0
- package/dist/share-data/helpers/get-array-string.d.ts.map +1 -0
- package/dist/share-data/helpers/get-array-string.js +17 -0
- package/dist/share-data/proofs/creation/build-transaction-proposal-signer.d.ts +57 -0
- package/dist/share-data/proofs/creation/build-transaction-proposal-signer.d.ts.map +1 -0
- package/dist/share-data/proofs/creation/build-transaction-proposal-signer.js +36 -0
- package/dist/share-data/proofs/creation/create-share-data-proposal-proof.d.ts +12 -0
- package/dist/share-data/proofs/creation/create-share-data-proposal-proof.d.ts.map +1 -0
- package/dist/share-data/proofs/creation/create-share-data-proposal-proof.js +41 -0
- package/dist/share-data/proofs/creation/create-transaction-proposal-proof.d.ts +27 -0
- package/dist/share-data/proofs/creation/create-transaction-proposal-proof.d.ts.map +1 -0
- package/dist/share-data/proofs/creation/create-transaction-proposal-proof.js +58 -0
- package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.d.ts +12 -0
- package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.d.ts.map +1 -0
- package/dist/share-data/proofs/helpers/create-share-data-string-to-sign.js +17 -0
- package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.d.ts +24 -0
- package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.d.ts.map +1 -0
- package/dist/share-data/proofs/helpers/create-transaction-proposal-string-to-sign.js +29 -0
- package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.d.ts +9 -0
- package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.d.ts.map +1 -0
- package/dist/share-data/proofs/helpers/get-previous-hash-from-share-data.js +28 -0
- package/dist/share-data/proofs/helpers/hash-proposed-state.d.ts +12 -0
- package/dist/share-data/proofs/helpers/hash-proposed-state.d.ts.map +1 -0
- package/dist/share-data/proofs/helpers/hash-proposed-state.js +18 -0
- package/dist/share-data/proofs/testing/test-proof-signer.d.ts +53 -0
- package/dist/share-data/proofs/testing/test-proof-signer.d.ts.map +1 -0
- package/dist/share-data/proofs/testing/test-proof-signer.js +113 -0
- package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.d.ts +40 -0
- package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.d.ts.map +1 -0
- package/dist/share-data/proofs/verification/verify-share-data-proposal-proof.js +126 -0
- package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.d.ts +37 -0
- package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.d.ts.map +1 -0
- package/dist/share-data/proofs/verification/verify-transaction-proposal-proof.js +125 -0
- package/dist/share-data/share-data.d.ts +232 -27
- package/dist/share-data/share-data.d.ts.map +1 -1
- package/dist/share-data/share-data.js +390 -60
- package/package.json +31 -13
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTransactionProposalStringToSign = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Builds the canonical string a transaction proposal proof signs over.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately distinct from `createShareDataStringToSign` (the structural /
|
|
8
|
+
* creation proof payload). A structural proof signs
|
|
9
|
+
* `${hash}${previousHash}${timestamp}` with no delimiters; this payload adds a
|
|
10
|
+
* `tx:` prefix, pipe delimiters, the *proposed* state hash, and the function
|
|
11
|
+
* id. Because the two signed strings can never collide, a structural proof's
|
|
12
|
+
* signature can never satisfy transaction verification and vice versa — the
|
|
13
|
+
* proof kinds are cryptographically non-interchangeable even though they share
|
|
14
|
+
* the `IShareDataCryptoProof` wire shape.
|
|
15
|
+
*
|
|
16
|
+
* The `proposedStateHash` component is what closes the runtime replay hole:
|
|
17
|
+
* the signature binds the exact post-transaction state, so a proof minted for
|
|
18
|
+
* a 1000-unit deposit cannot authorize a 9000-unit deposit.
|
|
19
|
+
*
|
|
20
|
+
* @param currentShareDataHash hash of the share-data state before the transaction
|
|
21
|
+
* @param proposedStateHash hash of the proposed (post-transaction) state
|
|
22
|
+
* @param functionId id of the function authorized to produce the proposed state
|
|
23
|
+
* @param previousShareDataHash previous hash anchoring the chain position
|
|
24
|
+
* @param timeStamp the timestamp folded into the signature
|
|
25
|
+
*/
|
|
26
|
+
const createTransactionProposalStringToSign = (currentShareDataHash, proposedStateHash, functionId, previousShareDataHash, timeStamp) => {
|
|
27
|
+
return `tx:${currentShareDataHash}|${proposedStateHash}|${functionId}|${previousShareDataHash}|${timeStamp}`;
|
|
28
|
+
};
|
|
29
|
+
exports.createTransactionProposalStringToSign = createTransactionProposalStringToSign;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ShareData } from '../../share-data';
|
|
2
|
+
/**
|
|
3
|
+
* This gets the previous hash from the share data object.
|
|
4
|
+
*
|
|
5
|
+
* @param shareData the share data object
|
|
6
|
+
* @returns the previous hash
|
|
7
|
+
*/
|
|
8
|
+
export declare const getPreviousHashFromShareData: (shareData: ShareData) => string;
|
|
9
|
+
//# sourceMappingURL=get-previous-hash-from-share-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-previous-hash-from-share-data.d.ts","sourceRoot":"","sources":["../../../../src/share-data/proofs/helpers/get-previous-hash-from-share-data.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,GAAI,WAAW,SAAS,KAAG,MAmBnE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPreviousHashFromShareData = void 0;
|
|
4
|
+
const generic_1 = require("@degenerate/generic");
|
|
5
|
+
/**
|
|
6
|
+
* This gets the previous hash from the share data object.
|
|
7
|
+
*
|
|
8
|
+
* @param shareData the share data object
|
|
9
|
+
* @returns the previous hash
|
|
10
|
+
*/
|
|
11
|
+
const getPreviousHashFromShareData = (shareData) => {
|
|
12
|
+
if (shareData.isLocked) {
|
|
13
|
+
if (shareData.cryptoProofs.length !== 0) {
|
|
14
|
+
return shareData.cryptoProofs[shareData.cryptoProofs.length - 1].shareDataHash;
|
|
15
|
+
}
|
|
16
|
+
return shareData.structuralProofs[shareData.structuralProofs.length - 1].shareDataHash;
|
|
17
|
+
}
|
|
18
|
+
if (shareData.structuralProofs.length !== 0) {
|
|
19
|
+
return shareData.structuralProofs[shareData.structuralProofs.length - 1].shareDataHash;
|
|
20
|
+
}
|
|
21
|
+
// If the share data is not locked and there are no structural proofs,
|
|
22
|
+
// then the creation hash is the previous hash
|
|
23
|
+
if (!shareData.creationHash) {
|
|
24
|
+
throw new generic_1.ShareDataPreviousHashNotAvailableError(shareData.id);
|
|
25
|
+
}
|
|
26
|
+
return shareData.creationHash;
|
|
27
|
+
};
|
|
28
|
+
exports.getPreviousHashFromShareData = getPreviousHashFromShareData;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IShareData } from '@degenerate/generic';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical hash of a proposed ShareData state.
|
|
4
|
+
*
|
|
5
|
+
* Uses the same serialization the default string config applies to the live
|
|
6
|
+
* `currentState` (`JSON.stringify` via `stringify`), so a proposed state
|
|
7
|
+
* hashes identically whether it is computed here at signing time or recomputed
|
|
8
|
+
* at verify time from the same object. Keeping this in one helper guarantees
|
|
9
|
+
* the signer and verifier never drift apart on how proposed state is hashed.
|
|
10
|
+
*/
|
|
11
|
+
export declare const hashProposedState: (proposedState: IShareData) => string;
|
|
12
|
+
//# sourceMappingURL=hash-proposed-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-proposed-state.d.ts","sourceRoot":"","sources":["../../../../src/share-data/proofs/helpers/hash-proposed-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGhE;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAAI,eAAe,UAAU,KAAG,MAE7D,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashProposedState = void 0;
|
|
4
|
+
const generic_1 = require("@degenerate/generic");
|
|
5
|
+
const stringify_1 = require("../../helpers/config/stringify");
|
|
6
|
+
/**
|
|
7
|
+
* Canonical hash of a proposed ShareData state.
|
|
8
|
+
*
|
|
9
|
+
* Uses the same serialization the default string config applies to the live
|
|
10
|
+
* `currentState` (`JSON.stringify` via `stringify`), so a proposed state
|
|
11
|
+
* hashes identically whether it is computed here at signing time or recomputed
|
|
12
|
+
* at verify time from the same object. Keeping this in one helper guarantees
|
|
13
|
+
* the signer and verifier never drift apart on how proposed state is hashed.
|
|
14
|
+
*/
|
|
15
|
+
const hashProposedState = (proposedState) => {
|
|
16
|
+
return (0, generic_1.calculateHash)((0, stringify_1.stringify)(proposedState));
|
|
17
|
+
};
|
|
18
|
+
exports.hashProposedState = hashProposedState;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EllipticalCurvesSigning, IShareData, IShareDataCryptoProof } from '@degenerate/generic';
|
|
2
|
+
import { ShareData } from '../../share-data';
|
|
3
|
+
/**
|
|
4
|
+
* Generate a fresh elliptic keypair suitable for signing ShareData proofs
|
|
5
|
+
* in tests. Returns the hex-encoded private and public keys so the caller
|
|
6
|
+
* can use the public half as the ShareData's `creationPublicKey` and the
|
|
7
|
+
* private half to mint real signed proofs.
|
|
8
|
+
*
|
|
9
|
+
* Test-only helper — not exported from the package barrel. Real signing
|
|
10
|
+
* keys must come from a key manager in production.
|
|
11
|
+
*/
|
|
12
|
+
export declare const generateTestSigningKey: (curve?: EllipticalCurvesSigning) => {
|
|
13
|
+
privateKey: string;
|
|
14
|
+
publicKey: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build a `(purpose, shareData) => IShareDataCryptoProof` callback that
|
|
18
|
+
* signs each requested proof with `privateKey`. On the very first call for
|
|
19
|
+
* a given `shareData`, initializes its crypto chain (matches
|
|
20
|
+
* `buildEllipticalCurvesProofFor` in `@degenerate/shareblock` — the two
|
|
21
|
+
* helpers serve the same role at different layers).
|
|
22
|
+
*
|
|
23
|
+
* Test-only helper. Production signing flows should use
|
|
24
|
+
* `buildEllipticalCurvesProofFor` from `@degenerate/shareblock` which
|
|
25
|
+
* handles the same plumbing through a documented public API.
|
|
26
|
+
*/
|
|
27
|
+
export declare const createTestProofFor: (privateKey: string, curve?: EllipticalCurvesSigning) => (purpose: string, shareData: ShareData) => IShareDataCryptoProof;
|
|
28
|
+
/**
|
|
29
|
+
* Build a `(proposedState, functionId, shareData) => IShareDataCryptoProof`
|
|
30
|
+
* callback that mints a *transaction* proposal proof (binds the proposed
|
|
31
|
+
* state + functionId, see `createTransactionProposalProof`). Use this for the
|
|
32
|
+
* runtime mutation path — `ShareData.addTransaction` /
|
|
33
|
+
* `ShareDataManager.applyTransaction` / realtime `propose` — where the proof
|
|
34
|
+
* must authorize one exact state change, unlike the structural proofs minted
|
|
35
|
+
* by {@link createTestProofFor}.
|
|
36
|
+
*
|
|
37
|
+
* Test-only helper. Production flows mint these from a key manager.
|
|
38
|
+
*/
|
|
39
|
+
export declare const createTestTransactionProofFor: (privateKey: string, curve?: EllipticalCurvesSigning) => (proposedState: IShareData, functionId: string, shareData: ShareData) => IShareDataCryptoProof;
|
|
40
|
+
/**
|
|
41
|
+
* Convenience wrapper: generate a fresh signing keypair AND return a
|
|
42
|
+
* matching proof signer in one call. Returns both so the test can use the
|
|
43
|
+
* public key when constructing the ShareData under test. `proofFor` mints
|
|
44
|
+
* structural proofs (addFunction/addRule); `transactionProofFor` mints
|
|
45
|
+
* runtime transaction proposal proofs.
|
|
46
|
+
*/
|
|
47
|
+
export declare const generateTestSigner: (curve?: EllipticalCurvesSigning) => {
|
|
48
|
+
privateKey: string;
|
|
49
|
+
publicKey: string;
|
|
50
|
+
proofFor: ReturnType<typeof createTestProofFor>;
|
|
51
|
+
transactionProofFor: ReturnType<typeof createTestTransactionProofFor>;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=test-proof-signer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-proof-signer.d.ts","sourceRoot":"","sources":["../../../../src/share-data/proofs/testing/test-proof-signer.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAC/B,QAAO,uBAA4D,KACpE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAOzC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAC3B,YAAY,MAAM,EAClB,QAAO,uBAA4D,MAE3D,SAAS,MAAM,EAAE,WAAW,SAAS,KAAG,qBAYnD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,GACtC,YAAY,MAAM,EAClB,QAAO,uBAA4D,MAG/D,eAAe,UAAU,EACzB,YAAY,MAAM,EAClB,WAAW,SAAS,KACrB,qBAEN,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC3B,QAAO,uBAA4D,KACpE;IACC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IAChD,mBAAmB,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAC;CASzE,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateTestSigner = exports.createTestTransactionProofFor = exports.createTestProofFor = exports.generateTestSigningKey = void 0;
|
|
37
|
+
/* eslint-disable new-cap */
|
|
38
|
+
const elliptic = __importStar(require("elliptic"));
|
|
39
|
+
const generic_1 = require("@degenerate/generic");
|
|
40
|
+
const create_share_data_initial_crypto_1 = require("../../creation/create-share-data-initial-crypto");
|
|
41
|
+
const create_share_data_proposal_proof_1 = require("../creation/create-share-data-proposal-proof");
|
|
42
|
+
const create_transaction_proposal_proof_1 = require("../creation/create-transaction-proposal-proof");
|
|
43
|
+
/**
|
|
44
|
+
* Generate a fresh elliptic keypair suitable for signing ShareData proofs
|
|
45
|
+
* in tests. Returns the hex-encoded private and public keys so the caller
|
|
46
|
+
* can use the public half as the ShareData's `creationPublicKey` and the
|
|
47
|
+
* private half to mint real signed proofs.
|
|
48
|
+
*
|
|
49
|
+
* Test-only helper — not exported from the package barrel. Real signing
|
|
50
|
+
* keys must come from a key manager in production.
|
|
51
|
+
*/
|
|
52
|
+
const generateTestSigningKey = (curve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
53
|
+
const ec = new elliptic.ec(curve);
|
|
54
|
+
const keyPair = ec.genKeyPair();
|
|
55
|
+
return {
|
|
56
|
+
privateKey: keyPair.getPrivate('hex'),
|
|
57
|
+
publicKey: keyPair.getPublic('hex'),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
exports.generateTestSigningKey = generateTestSigningKey;
|
|
61
|
+
/**
|
|
62
|
+
* Build a `(purpose, shareData) => IShareDataCryptoProof` callback that
|
|
63
|
+
* signs each requested proof with `privateKey`. On the very first call for
|
|
64
|
+
* a given `shareData`, initializes its crypto chain (matches
|
|
65
|
+
* `buildEllipticalCurvesProofFor` in `@degenerate/shareblock` — the two
|
|
66
|
+
* helpers serve the same role at different layers).
|
|
67
|
+
*
|
|
68
|
+
* Test-only helper. Production signing flows should use
|
|
69
|
+
* `buildEllipticalCurvesProofFor` from `@degenerate/shareblock` which
|
|
70
|
+
* handles the same plumbing through a documented public API.
|
|
71
|
+
*/
|
|
72
|
+
const createTestProofFor = (privateKey, curve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
73
|
+
return (purpose, shareData) => {
|
|
74
|
+
if (!shareData.creationHash && shareData.structuralProofs.length === 0) {
|
|
75
|
+
const initialCrypto = (0, create_share_data_initial_crypto_1.createShareDataInitialCrypto)(privateKey, shareData, curve);
|
|
76
|
+
shareData.initializeCrypto(initialCrypto);
|
|
77
|
+
}
|
|
78
|
+
return (0, create_share_data_proposal_proof_1.createShareDataProposalProof)(privateKey, shareData, { purpose }, curve);
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
exports.createTestProofFor = createTestProofFor;
|
|
82
|
+
/**
|
|
83
|
+
* Build a `(proposedState, functionId, shareData) => IShareDataCryptoProof`
|
|
84
|
+
* callback that mints a *transaction* proposal proof (binds the proposed
|
|
85
|
+
* state + functionId, see `createTransactionProposalProof`). Use this for the
|
|
86
|
+
* runtime mutation path — `ShareData.addTransaction` /
|
|
87
|
+
* `ShareDataManager.applyTransaction` / realtime `propose` — where the proof
|
|
88
|
+
* must authorize one exact state change, unlike the structural proofs minted
|
|
89
|
+
* by {@link createTestProofFor}.
|
|
90
|
+
*
|
|
91
|
+
* Test-only helper. Production flows mint these from a key manager.
|
|
92
|
+
*/
|
|
93
|
+
const createTestTransactionProofFor = (privateKey, curve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
94
|
+
return (proposedState, functionId, shareData) => (0, create_transaction_proposal_proof_1.createTransactionProposalProof)(privateKey, shareData, proposedState, functionId, curve);
|
|
95
|
+
};
|
|
96
|
+
exports.createTestTransactionProofFor = createTestTransactionProofFor;
|
|
97
|
+
/**
|
|
98
|
+
* Convenience wrapper: generate a fresh signing keypair AND return a
|
|
99
|
+
* matching proof signer in one call. Returns both so the test can use the
|
|
100
|
+
* public key when constructing the ShareData under test. `proofFor` mints
|
|
101
|
+
* structural proofs (addFunction/addRule); `transactionProofFor` mints
|
|
102
|
+
* runtime transaction proposal proofs.
|
|
103
|
+
*/
|
|
104
|
+
const generateTestSigner = (curve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
105
|
+
const { privateKey, publicKey } = (0, exports.generateTestSigningKey)(curve);
|
|
106
|
+
return {
|
|
107
|
+
privateKey,
|
|
108
|
+
publicKey,
|
|
109
|
+
proofFor: (0, exports.createTestProofFor)(privateKey, curve),
|
|
110
|
+
transactionProofFor: (0, exports.createTestTransactionProofFor)(privateKey, curve),
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
exports.generateTestSigner = generateTestSigner;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EllipticalCurvesSigning, IShareDataCryptoProof } from '@degenerate/generic';
|
|
2
|
+
import { ShareData } from '../../share-data';
|
|
3
|
+
/**
|
|
4
|
+
* Verifies that an `IShareDataCryptoProof` is a faithful attestation of the
|
|
5
|
+
* supplied `shareData`'s structural state. Returns `true` on success; throws
|
|
6
|
+
* {@link ShareDataStructuralProofFailedError} on any failure.
|
|
7
|
+
*
|
|
8
|
+
* The `purpose` to verify under is read from `proof.purpose` — proofs are
|
|
9
|
+
* self-describing so callers don't need to remember which purpose to verify
|
|
10
|
+
* with. This also means an attacker can't shift a proof's purpose to bypass
|
|
11
|
+
* verification (they'd need a fresh signature for the new purpose, which
|
|
12
|
+
* requires the private key).
|
|
13
|
+
*
|
|
14
|
+
* Synchronous on purpose — `addFunction` / `addRule` are synchronous and we
|
|
15
|
+
* don't want to cascade-async every caller in the codebase.
|
|
16
|
+
* `elliptic.ec().keyFromPublic().verify()` is itself synchronous; the
|
|
17
|
+
* project's existing `verifyCryptoSignatureByHash` wrapper is `async` only
|
|
18
|
+
* cosmetically.
|
|
19
|
+
*
|
|
20
|
+
* Verification proceeds in this order:
|
|
21
|
+
* 1. Recompute the canonical share-data string + hash, folding in
|
|
22
|
+
* `proof.purpose`. If the proof's `shareDataHash` doesn't match,
|
|
23
|
+
* reject. (Catches "proof signed against different state.")
|
|
24
|
+
* 2. Recompute the previous hash from the chain. If the proof's
|
|
25
|
+
* `shareDataPreviousHash` doesn't match, reject. (Catches "proof claims
|
|
26
|
+
* a different chain position.")
|
|
27
|
+
* 3. Reconstruct the signed string from the proof's now-validated hash,
|
|
28
|
+
* previousHash, and timestamp, and verify the signature against the
|
|
29
|
+
* proof's `publicKey`. (Catches "signature was tampered or signed with
|
|
30
|
+
* a different key.")
|
|
31
|
+
*
|
|
32
|
+
* The order matters: skipping step 1 or 2 and going straight to signature
|
|
33
|
+
* verification would accept an attacker-crafted proof that claims to attest
|
|
34
|
+
* to one state while the actual share-data has a different state — the
|
|
35
|
+
* signature alone only proves the publicKey holder signed the
|
|
36
|
+
* `(hash, previousHash, timestamp)` triple, not that the hash matches
|
|
37
|
+
* anything real.
|
|
38
|
+
*/
|
|
39
|
+
export declare const verifyShareDataProposalProof: (proof: IShareDataCryptoProof, shareData: ShareData, ellipticalCurve?: EllipticalCurvesSigning) => true;
|
|
40
|
+
//# sourceMappingURL=verify-share-data-proposal-proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-share-data-proposal-proof.d.ts","sourceRoot":"","sources":["../../../../src/share-data/proofs/verification/verify-share-data-proposal-proof.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,uBAAuB,EACvB,qBAAqB,EAExB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,4BAA4B,GACrC,OAAO,qBAAqB,EAC5B,WAAW,SAAS,EACpB,kBAAiB,uBAA4D,KAC9E,IAoDF,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.verifyShareDataProposalProof = void 0;
|
|
37
|
+
const elliptic = __importStar(require("elliptic"));
|
|
38
|
+
const generic_1 = require("@degenerate/generic");
|
|
39
|
+
const calculate_share_data_string_1 = require("../../helpers/calculate-share-data-string");
|
|
40
|
+
const get_previous_hash_from_share_data_1 = require("../helpers/get-previous-hash-from-share-data");
|
|
41
|
+
const create_share_data_string_to_sign_1 = require("../helpers/create-share-data-string-to-sign");
|
|
42
|
+
/**
|
|
43
|
+
* Verifies that an `IShareDataCryptoProof` is a faithful attestation of the
|
|
44
|
+
* supplied `shareData`'s structural state. Returns `true` on success; throws
|
|
45
|
+
* {@link ShareDataStructuralProofFailedError} on any failure.
|
|
46
|
+
*
|
|
47
|
+
* The `purpose` to verify under is read from `proof.purpose` — proofs are
|
|
48
|
+
* self-describing so callers don't need to remember which purpose to verify
|
|
49
|
+
* with. This also means an attacker can't shift a proof's purpose to bypass
|
|
50
|
+
* verification (they'd need a fresh signature for the new purpose, which
|
|
51
|
+
* requires the private key).
|
|
52
|
+
*
|
|
53
|
+
* Synchronous on purpose — `addFunction` / `addRule` are synchronous and we
|
|
54
|
+
* don't want to cascade-async every caller in the codebase.
|
|
55
|
+
* `elliptic.ec().keyFromPublic().verify()` is itself synchronous; the
|
|
56
|
+
* project's existing `verifyCryptoSignatureByHash` wrapper is `async` only
|
|
57
|
+
* cosmetically.
|
|
58
|
+
*
|
|
59
|
+
* Verification proceeds in this order:
|
|
60
|
+
* 1. Recompute the canonical share-data string + hash, folding in
|
|
61
|
+
* `proof.purpose`. If the proof's `shareDataHash` doesn't match,
|
|
62
|
+
* reject. (Catches "proof signed against different state.")
|
|
63
|
+
* 2. Recompute the previous hash from the chain. If the proof's
|
|
64
|
+
* `shareDataPreviousHash` doesn't match, reject. (Catches "proof claims
|
|
65
|
+
* a different chain position.")
|
|
66
|
+
* 3. Reconstruct the signed string from the proof's now-validated hash,
|
|
67
|
+
* previousHash, and timestamp, and verify the signature against the
|
|
68
|
+
* proof's `publicKey`. (Catches "signature was tampered or signed with
|
|
69
|
+
* a different key.")
|
|
70
|
+
*
|
|
71
|
+
* The order matters: skipping step 1 or 2 and going straight to signature
|
|
72
|
+
* verification would accept an attacker-crafted proof that claims to attest
|
|
73
|
+
* to one state while the actual share-data has a different state — the
|
|
74
|
+
* signature alone only proves the publicKey holder signed the
|
|
75
|
+
* `(hash, previousHash, timestamp)` triple, not that the hash matches
|
|
76
|
+
* anything real.
|
|
77
|
+
*/
|
|
78
|
+
const verifyShareDataProposalProof = (proof, shareData, ellipticalCurve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
79
|
+
// Step 1: hash of current state matches what the proof claims. The
|
|
80
|
+
// purpose comes from the proof itself, so a tampered purpose produces
|
|
81
|
+
// a different hash and gets caught here.
|
|
82
|
+
const shareDataString = (0, calculate_share_data_string_1.calculateShareDataString)(shareData, undefined, { purpose: proof.purpose });
|
|
83
|
+
const recomputedHash = (0, generic_1.calculateHash)(shareDataString);
|
|
84
|
+
if (recomputedHash !== proof.shareDataHash) {
|
|
85
|
+
throw new generic_1.ShareDataStructuralProofFailedError(shareData.id);
|
|
86
|
+
}
|
|
87
|
+
// Step 2: previous-hash matches the chain.
|
|
88
|
+
let recomputedPreviousHash;
|
|
89
|
+
try {
|
|
90
|
+
recomputedPreviousHash = (0, get_previous_hash_from_share_data_1.getPreviousHashFromShareData)(shareData);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// ShareDataPreviousHashNotAvailableError — chain is in a state
|
|
94
|
+
// where no previous hash exists. The proof should not be claiming
|
|
95
|
+
// one either.
|
|
96
|
+
throw new generic_1.ShareDataStructuralProofFailedError(shareData.id);
|
|
97
|
+
}
|
|
98
|
+
if (recomputedPreviousHash !== proof.shareDataPreviousHash) {
|
|
99
|
+
throw new generic_1.ShareDataStructuralProofFailedError(shareData.id);
|
|
100
|
+
}
|
|
101
|
+
// Step 3: signature verifies against the proof's publicKey for the
|
|
102
|
+
// (now-validated) hash + previousHash + timestamp triple.
|
|
103
|
+
const signedString = (0, create_share_data_string_to_sign_1.createShareDataStringToSign)(proof.shareDataHash, proof.shareDataPreviousHash, proof.timestamp);
|
|
104
|
+
let signatureValid;
|
|
105
|
+
try {
|
|
106
|
+
// eslint-disable-next-line new-cap
|
|
107
|
+
const key = new elliptic.ec(ellipticalCurve).keyFromPublic(proof.publicKey, 'hex');
|
|
108
|
+
// Mirror the hash-before-sign step in `createEllipticalCurveSignature`
|
|
109
|
+
// so the verifier sees the same fixed-size 256-bit digest the signer
|
|
110
|
+
// operated on. Without this, elliptic's ECDSA on ed25519 silently
|
|
111
|
+
// truncates inputs longer than ~253 bits and the signature stops
|
|
112
|
+
// binding the trailing bytes (timestamp, tail of previousHash).
|
|
113
|
+
const digest = (0, generic_1.calculateHash)(signedString);
|
|
114
|
+
signatureValid = key.verify(digest, proof.shareDataSignature);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// elliptic throws on malformed signature/key strings rather than
|
|
118
|
+
// returning false — normalize to a single rejection mode.
|
|
119
|
+
throw new generic_1.ShareDataStructuralProofFailedError(shareData.id);
|
|
120
|
+
}
|
|
121
|
+
if (!signatureValid) {
|
|
122
|
+
throw new generic_1.ShareDataStructuralProofFailedError(shareData.id);
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
};
|
|
126
|
+
exports.verifyShareDataProposalProof = verifyShareDataProposalProof;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EllipticalCurvesSigning, IShareData, IShareDataCryptoProof } from '@degenerate/generic';
|
|
2
|
+
import { ShareData } from '../../share-data';
|
|
3
|
+
/**
|
|
4
|
+
* Verify a transaction proposal proof against the live `shareData` and the
|
|
5
|
+
* `proposedState` the caller intends to apply. Returns `true`; throws
|
|
6
|
+
* {@link ShareDataTransactionProofFailedError} on any mismatch.
|
|
7
|
+
*
|
|
8
|
+
* This is the runtime counterpart to `verifyShareDataProposalProof`. The
|
|
9
|
+
* critical extra step over the structural verifier is step 2: it recomputes
|
|
10
|
+
* the hash of the *proposed* state the caller is about to apply and folds it
|
|
11
|
+
* into the reconstructed signed string. A proof minted for one proposed state
|
|
12
|
+
* therefore fails for any other — the runtime replay hole is closed here, at
|
|
13
|
+
* the verification boundary, not by trusting the transport.
|
|
14
|
+
*
|
|
15
|
+
* Verification order:
|
|
16
|
+
* 1. Recompute the current-state hash (purpose = `proof.purpose` =
|
|
17
|
+
* functionId); it must equal `proof.shareDataHash`. (Catches "proof
|
|
18
|
+
* signed against a different current state.")
|
|
19
|
+
* 2. Recompute the proposed-state hash from `proposedState`. (Binds the
|
|
20
|
+
* exact state being applied.)
|
|
21
|
+
* 3. Recompute the previous hash from the chain; it must equal
|
|
22
|
+
* `proof.shareDataPreviousHash`. (Catches "proof claims a different
|
|
23
|
+
* chain position.")
|
|
24
|
+
* 4. Reconstruct the transaction signed string from the validated current
|
|
25
|
+
* hash, the recomputed proposed hash, the function id, the previous
|
|
26
|
+
* hash, and the timestamp, and verify the signature against
|
|
27
|
+
* `proof.publicKey`.
|
|
28
|
+
*
|
|
29
|
+
* Because the reconstructed string carries the `tx:` prefix and the proposed
|
|
30
|
+
* hash, a structural proof's signature can never satisfy this check — the two
|
|
31
|
+
* proof kinds are non-interchangeable.
|
|
32
|
+
*
|
|
33
|
+
* Synchronous to match the rest of the proof pipeline; elliptic's `verify`
|
|
34
|
+
* is itself synchronous.
|
|
35
|
+
*/
|
|
36
|
+
export declare const verifyTransactionProposalProof: (proof: IShareDataCryptoProof, shareData: ShareData, proposedState: IShareData, ellipticalCurve?: EllipticalCurvesSigning) => true;
|
|
37
|
+
//# sourceMappingURL=verify-transaction-proposal-proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-transaction-proposal-proof.d.ts","sourceRoot":"","sources":["../../../../src/share-data/proofs/verification/verify-transaction-proposal-proof.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EAExB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,8BAA8B,GACvC,OAAO,qBAAqB,EAC5B,WAAW,SAAS,EACpB,eAAe,UAAU,EACzB,kBAAiB,uBAA4D,KAC9E,IAwDF,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.verifyTransactionProposalProof = void 0;
|
|
37
|
+
const elliptic = __importStar(require("elliptic"));
|
|
38
|
+
const generic_1 = require("@degenerate/generic");
|
|
39
|
+
const calculate_share_data_string_1 = require("../../helpers/calculate-share-data-string");
|
|
40
|
+
const get_previous_hash_from_share_data_1 = require("../helpers/get-previous-hash-from-share-data");
|
|
41
|
+
const create_transaction_proposal_string_to_sign_1 = require("../helpers/create-transaction-proposal-string-to-sign");
|
|
42
|
+
const hash_proposed_state_1 = require("../helpers/hash-proposed-state");
|
|
43
|
+
/**
|
|
44
|
+
* Verify a transaction proposal proof against the live `shareData` and the
|
|
45
|
+
* `proposedState` the caller intends to apply. Returns `true`; throws
|
|
46
|
+
* {@link ShareDataTransactionProofFailedError} on any mismatch.
|
|
47
|
+
*
|
|
48
|
+
* This is the runtime counterpart to `verifyShareDataProposalProof`. The
|
|
49
|
+
* critical extra step over the structural verifier is step 2: it recomputes
|
|
50
|
+
* the hash of the *proposed* state the caller is about to apply and folds it
|
|
51
|
+
* into the reconstructed signed string. A proof minted for one proposed state
|
|
52
|
+
* therefore fails for any other — the runtime replay hole is closed here, at
|
|
53
|
+
* the verification boundary, not by trusting the transport.
|
|
54
|
+
*
|
|
55
|
+
* Verification order:
|
|
56
|
+
* 1. Recompute the current-state hash (purpose = `proof.purpose` =
|
|
57
|
+
* functionId); it must equal `proof.shareDataHash`. (Catches "proof
|
|
58
|
+
* signed against a different current state.")
|
|
59
|
+
* 2. Recompute the proposed-state hash from `proposedState`. (Binds the
|
|
60
|
+
* exact state being applied.)
|
|
61
|
+
* 3. Recompute the previous hash from the chain; it must equal
|
|
62
|
+
* `proof.shareDataPreviousHash`. (Catches "proof claims a different
|
|
63
|
+
* chain position.")
|
|
64
|
+
* 4. Reconstruct the transaction signed string from the validated current
|
|
65
|
+
* hash, the recomputed proposed hash, the function id, the previous
|
|
66
|
+
* hash, and the timestamp, and verify the signature against
|
|
67
|
+
* `proof.publicKey`.
|
|
68
|
+
*
|
|
69
|
+
* Because the reconstructed string carries the `tx:` prefix and the proposed
|
|
70
|
+
* hash, a structural proof's signature can never satisfy this check — the two
|
|
71
|
+
* proof kinds are non-interchangeable.
|
|
72
|
+
*
|
|
73
|
+
* Synchronous to match the rest of the proof pipeline; elliptic's `verify`
|
|
74
|
+
* is itself synchronous.
|
|
75
|
+
*/
|
|
76
|
+
const verifyTransactionProposalProof = (proof, shareData, proposedState, ellipticalCurve = generic_1.EllipticalCurvesSigning.Curve25519) => {
|
|
77
|
+
// Step 1: current-state hash matches what the proof claims. The purpose
|
|
78
|
+
// (functionId) comes from the proof itself, so a tampered purpose
|
|
79
|
+
// produces a different hash and is caught here.
|
|
80
|
+
const currentString = (0, calculate_share_data_string_1.calculateShareDataString)(shareData, undefined, { purpose: proof.purpose });
|
|
81
|
+
const recomputedCurrentHash = (0, generic_1.calculateHash)(currentString);
|
|
82
|
+
if (recomputedCurrentHash !== proof.shareDataHash) {
|
|
83
|
+
throw new generic_1.ShareDataTransactionProofFailedError(shareData.id);
|
|
84
|
+
}
|
|
85
|
+
// Step 2: hash the proposed state being applied so it can be folded into
|
|
86
|
+
// the reconstructed signature payload.
|
|
87
|
+
const proposedStateHash = (0, hash_proposed_state_1.hashProposedState)(proposedState);
|
|
88
|
+
// Step 3: previous-hash matches the chain.
|
|
89
|
+
let recomputedPreviousHash;
|
|
90
|
+
try {
|
|
91
|
+
recomputedPreviousHash = (0, get_previous_hash_from_share_data_1.getPreviousHashFromShareData)(shareData);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ShareDataPreviousHashNotAvailableError — chain has no previous hash;
|
|
95
|
+
// the proof should not be claiming one either.
|
|
96
|
+
throw new generic_1.ShareDataTransactionProofFailedError(shareData.id);
|
|
97
|
+
}
|
|
98
|
+
if (recomputedPreviousHash !== proof.shareDataPreviousHash) {
|
|
99
|
+
throw new generic_1.ShareDataTransactionProofFailedError(shareData.id);
|
|
100
|
+
}
|
|
101
|
+
// Step 4: signature verifies over the full transaction payload (which
|
|
102
|
+
// includes the proposed-state hash and the `tx:` discriminator).
|
|
103
|
+
const signedString = (0, create_transaction_proposal_string_to_sign_1.createTransactionProposalStringToSign)(proof.shareDataHash, proposedStateHash, proof.purpose, proof.shareDataPreviousHash, proof.timestamp);
|
|
104
|
+
let signatureValid;
|
|
105
|
+
try {
|
|
106
|
+
// eslint-disable-next-line new-cap
|
|
107
|
+
const key = new elliptic.ec(ellipticalCurve).keyFromPublic(proof.publicKey, 'hex');
|
|
108
|
+
// Mirror the hash-before-sign step in `createEllipticalCurveSignature`
|
|
109
|
+
// so the verifier operates on the same fixed-size digest the signer
|
|
110
|
+
// did. Without this, elliptic's ECDSA on ed25519 silently truncates
|
|
111
|
+
// long inputs and stops binding the trailing bytes.
|
|
112
|
+
const digest = (0, generic_1.calculateHash)(signedString);
|
|
113
|
+
signatureValid = key.verify(digest, proof.shareDataSignature);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// elliptic throws on malformed signature/key strings rather than
|
|
117
|
+
// returning false — normalize to a single rejection mode.
|
|
118
|
+
throw new generic_1.ShareDataTransactionProofFailedError(shareData.id);
|
|
119
|
+
}
|
|
120
|
+
if (!signatureValid) {
|
|
121
|
+
throw new generic_1.ShareDataTransactionProofFailedError(shareData.id);
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
};
|
|
125
|
+
exports.verifyTransactionProposalProof = verifyTransactionProposalProof;
|