@sig-net/midnight 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/constants.d.ts +62 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +83 -0
- package/dist/constants.js.map +1 -0
- package/dist/epsilon-derivation.d.ts +32 -0
- package/dist/epsilon-derivation.d.ts.map +1 -0
- package/dist/epsilon-derivation.js +54 -0
- package/dist/epsilon-derivation.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/managed/compiler/contract-info.json +165 -0
- package/dist/managed/compiler/contract-manifest.json +32 -0
- package/dist/managed/contract/index.d.ts +65 -0
- package/dist/managed/contract/index.js +611 -0
- package/dist/managed/contract/index.js.map +8 -0
- package/dist/schnorr.d.ts +100 -0
- package/dist/schnorr.d.ts.map +1 -0
- package/dist/schnorr.js +144 -0
- package/dist/schnorr.js.map +1 -0
- package/dist/signature-requests-state-reader.d.ts +74 -0
- package/dist/signature-requests-state-reader.d.ts.map +1 -0
- package/dist/signature-requests-state-reader.js +167 -0
- package/dist/signature-requests-state-reader.js.map +1 -0
- package/dist/signature-response-verification.d.ts +27 -0
- package/dist/signature-response-verification.d.ts.map +1 -0
- package/dist/signature-response-verification.js +45 -0
- package/dist/signature-response-verification.js.map +1 -0
- package/dist/signature-state-reading.d.ts +36 -0
- package/dist/signature-state-reading.d.ts.map +1 -0
- package/dist/signature-state-reading.js +62 -0
- package/dist/signature-state-reading.js.map +1 -0
- package/dist/signet-contract-state-reader.d.ts +146 -0
- package/dist/signet-contract-state-reader.d.ts.map +1 -0
- package/dist/signet-contract-state-reader.js +226 -0
- package/dist/signet-contract-state-reader.js.map +1 -0
- package/dist/signet-event-observer.d.ts +102 -0
- package/dist/signet-event-observer.d.ts.map +1 -0
- package/dist/signet-event-observer.js +127 -0
- package/dist/signet-event-observer.js.map +1 -0
- package/dist/signet-events.d.ts +175 -0
- package/dist/signet-events.d.ts.map +1 -0
- package/dist/signet-events.js +210 -0
- package/dist/signet-events.js.map +1 -0
- package/dist/signet-request-feed.d.ts +78 -0
- package/dist/signet-request-feed.d.ts.map +1 -0
- package/dist/signet-request-feed.js +116 -0
- package/dist/signet-request-feed.js.map +1 -0
- package/dist/signet-request-resolver.d.ts +58 -0
- package/dist/signet-request-resolver.d.ts.map +1 -0
- package/dist/signet-request-resolver.js +76 -0
- package/dist/signet-request-resolver.js.map +1 -0
- package/dist/signet-request-response-reader.d.ts +160 -0
- package/dist/signet-request-response-reader.d.ts.map +1 -0
- package/dist/signet-request-response-reader.js +198 -0
- package/dist/signet-request-response-reader.js.map +1 -0
- package/dist/signet-requests.d.ts +363 -0
- package/dist/signet-requests.d.ts.map +1 -0
- package/dist/signet-requests.js +497 -0
- package/dist/signet-requests.js.map +1 -0
- package/dist/signet-response-feed.d.ts +161 -0
- package/dist/signet-response-feed.d.ts.map +1 -0
- package/dist/signet-response-feed.js +234 -0
- package/dist/signet-response-feed.js.map +1 -0
- package/package.json +47 -0
- package/src/Schnorr.compact +63 -0
- package/src/Signet.compact +529 -0
- package/src/circuits.compact +36 -0
- package/src/constants.ts +97 -0
- package/src/epsilon-derivation.ts +62 -0
- package/src/index.ts +31 -0
- package/src/managed/compiler/contract-info.json +165 -0
- package/src/managed/compiler/contract-manifest.json +32 -0
- package/src/managed/contract/index.d.ts +65 -0
- package/src/managed/contract/index.js +611 -0
- package/src/managed/contract/index.js.map +8 -0
- package/src/schnorr.ts +210 -0
- package/src/signature-requests-state-reader.ts +223 -0
- package/src/signature-response-verification.ts +64 -0
- package/src/signature-state-reading.ts +87 -0
- package/src/signet-contract-state-reader.ts +391 -0
- package/src/signet-event-observer.ts +186 -0
- package/src/signet-events.ts +337 -0
- package/src/signet-request-feed.ts +158 -0
- package/src/signet-request-resolver.ts +116 -0
- package/src/signet-request-response-reader.ts +324 -0
- package/src/signet-requests.ts +737 -0
- package/src/signet-response-feed.ts +325 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type JubjubPoint } from "@midnight-ntwrk/compact-runtime";
|
|
2
|
+
export type { JubjubPoint } from "@midnight-ntwrk/compact-runtime";
|
|
3
|
+
/** Jubjub curve scalar field order (group order of the generator). */
|
|
4
|
+
export declare const JUBJUB_ORDER = 6554484396890773809930967563523245729705921265872317281365359162392183254199n;
|
|
5
|
+
/** BLS12-381 scalar field order (the Compact `Field` type modulus). */
|
|
6
|
+
export declare const BLS_ORDER = 52435875175126190479447740508185965837690552500527637822603658699938581184513n;
|
|
7
|
+
/**
|
|
8
|
+
* Convert little-endian bytes to a bigint. Matches Compact's
|
|
9
|
+
* `Bytes<32> as Field` interpretation (and the MPC monitor's ABI-word
|
|
10
|
+
* decoding convention).
|
|
11
|
+
*
|
|
12
|
+
* @param bytes - Little-endian byte array.
|
|
13
|
+
* @returns The decoded non-negative integer.
|
|
14
|
+
*/
|
|
15
|
+
export declare function bytesToBigint(bytes: Uint8Array): bigint;
|
|
16
|
+
/**
|
|
17
|
+
* Convert a bigint to exactly 32 little-endian bytes. Matches Compact's
|
|
18
|
+
* `Field as Bytes<32>` encoding (the inverse of {@link bytesToBigint});
|
|
19
|
+
* negative inputs are interpreted in the BLS scalar field.
|
|
20
|
+
*
|
|
21
|
+
* @param n - The integer to encode.
|
|
22
|
+
* @returns The 32-byte little-endian encoding.
|
|
23
|
+
*/
|
|
24
|
+
export declare function bigintToBytes32(n: bigint): Uint8Array;
|
|
25
|
+
/** A Jubjub keypair: the secret scalar and its public curve point. */
|
|
26
|
+
export interface JubjubKeypair {
|
|
27
|
+
/** Secret scalar in `[1, JUBJUB_ORDER - 1]`. */
|
|
28
|
+
sk: bigint;
|
|
29
|
+
/** Public key: `sk * G` on Jubjub. */
|
|
30
|
+
pk: JubjubPoint;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Derive a Jubjub keypair from a seed — the same derivation the MPC server
|
|
34
|
+
* performs on its root key, so this MUST stay bit-identical to it:
|
|
35
|
+
* `sk = (persistentHash([pad32("jubjub:auth:"), seed]) mod (order - 1)) + 1`,
|
|
36
|
+
* `pk = sk * G`.
|
|
37
|
+
*
|
|
38
|
+
* @param seed - Seed bytes (e.g. the 32-byte MPC root key).
|
|
39
|
+
* @returns The derived {@link JubjubKeypair}.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveJubjubKeypair(seed: Uint8Array): JubjubKeypair;
|
|
42
|
+
/**
|
|
43
|
+
* A Schnorr signature (TS twin of CompactStandardLibrary's
|
|
44
|
+
* `JubjubSchnorrSignature`).
|
|
45
|
+
*/
|
|
46
|
+
export interface SchnorrSignature {
|
|
47
|
+
/** Nonce commitment R = k * G. */
|
|
48
|
+
announcement: JubjubPoint;
|
|
49
|
+
/** Signature scalar s = (k + c * sk) mod JUBJUB_ORDER. */
|
|
50
|
+
response: bigint;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Computes the Schnorr challenge (the Poseidon transientHash output reduced
|
|
54
|
+
* into Jubjub's scalar field, exactly as `jubjubSchnorrVerify` computes it).
|
|
55
|
+
* ALWAYS inject the compiled circuit — signet-midnight's own
|
|
56
|
+
* `pureCircuits.schnorrChallenge` — never a TS re-implementation; keeping it
|
|
57
|
+
* injected keeps this signer decoupled from any one compiled artifact.
|
|
58
|
+
*/
|
|
59
|
+
export type SchnorrChallengeFn = (annX: bigint, annY: bigint, pkX: bigint, pkY: bigint, msg: bigint[]) => bigint;
|
|
60
|
+
/**
|
|
61
|
+
* Sign a message with Schnorr on Jubjub, matching CompactStandardLibrary's
|
|
62
|
+
* `jubjubSchnorrVerify`: `c = challenge` (already reduced into Jubjub's
|
|
63
|
+
* scalar field by the compiled circuit), `s = (k + c * sk) mod JUBJUB_ORDER`.
|
|
64
|
+
* For signet attestations the message is the compiled
|
|
65
|
+
* `pureCircuits.signetAttestationMessage(requestId, outputData)`.
|
|
66
|
+
*
|
|
67
|
+
* @param sk - Jubjub private key scalar.
|
|
68
|
+
* @param msg - Message field limbs.
|
|
69
|
+
* @param schnorrChallenge - The compiled `pureCircuits.schnorrChallenge`.
|
|
70
|
+
* @returns The signature (announcement R, response s).
|
|
71
|
+
* @throws Error if `sk` reduces to zero mod the Jubjub order.
|
|
72
|
+
*/
|
|
73
|
+
export declare function schnorrSign(sk: bigint, msg: bigint[], schnorrChallenge: SchnorrChallengeFn): SchnorrSignature;
|
|
74
|
+
/**
|
|
75
|
+
* Hash a Jubjub point exactly as the circuits do (`persistentHash<JubjubPoint>`)
|
|
76
|
+
* — the form the signet contract seals as `mpcPubKeyHash`.
|
|
77
|
+
*
|
|
78
|
+
* @param point - The point to hash.
|
|
79
|
+
* @returns The 32-byte hash.
|
|
80
|
+
*/
|
|
81
|
+
export declare function hashJubjubPoint(point: JubjubPoint): Uint8Array;
|
|
82
|
+
/**
|
|
83
|
+
* Parse a Jubjub public key from its `"x,y"` config/env form (decimal or
|
|
84
|
+
* 0x-hex field coordinates) — how deploys receive `MPC_JUBJUB_PK`.
|
|
85
|
+
*
|
|
86
|
+
* @param value - The `"x,y"` string.
|
|
87
|
+
* @returns The parsed point.
|
|
88
|
+
* @throws Error if the value is not two comma-separated field coordinates.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseJubjubPublicKey(value: string): JubjubPoint;
|
|
91
|
+
/**
|
|
92
|
+
* Format a Jubjub public key as the `"x,y"` decimal config/env form that
|
|
93
|
+
* {@link parseJubjubPublicKey} accepts — the round-trip inverse, for handing
|
|
94
|
+
* a derived key to deploys as `MPC_JUBJUB_PK`.
|
|
95
|
+
*
|
|
96
|
+
* @param point - The point to format.
|
|
97
|
+
* @returns The `"x,y"` string with decimal coordinates.
|
|
98
|
+
*/
|
|
99
|
+
export declare function formatJubjubPublicKey(point: JubjubPoint): string;
|
|
100
|
+
//# sourceMappingURL=schnorr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schnorr.d.ts","sourceRoot":"","sources":["../src/schnorr.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,iCAAiC,CAAC;AAKzC,YAAY,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,sEAAsE;AACtE,eAAO,MAAM,YAAY,gFAAgF,CAAC;AAE1G,uEAAuE;AACvE,eAAO,MAAM,SAAS,iFAAiF,CAAC;AAKxG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAQrD;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,EAAE,EAAE,WAAW,CAAC;CACjB;AASD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,aAAa,CAKnE;AAID;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,YAAY,EAAE,WAAW,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EAAE,KACV,MAAM,CAAC;AAEZ;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EAAE,EACb,gBAAgB,EAAE,kBAAkB,GACnC,gBAAgB,CAgBlB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAU/D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEhE"}
|
package/dist/schnorr.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Jubjub Schnorr helpers — the TS side of the shared Schnorr.compact module:
|
|
2
|
+
// key derivation, SIGNING (which needs the secret scalar, so it cannot be a
|
|
3
|
+
// circuit), and key parsing/hashing. Everything provable stays in Compact:
|
|
4
|
+
// the challenge is the COMPILED `pureCircuits.schnorrChallenge`, injected by
|
|
5
|
+
// callers (see SchnorrChallengeFn), and the attestation message is the
|
|
6
|
+
// compiled `pureCircuits.signetAttestationMessage` — this file never
|
|
7
|
+
// re-implements either. Verification lives in circuits only
|
|
8
|
+
// (CompactStandardLibrary's jubjubSchnorrVerify, run by the signet contract
|
|
9
|
+
// at post time).
|
|
10
|
+
//
|
|
11
|
+
// This belongs in github.com/sig-net/signet.js as its Midnight adapter —
|
|
12
|
+
// kept here until upstreamed. The math is Midnight-specific (Jubjub embedded
|
|
13
|
+
// in BLS12-381 via @midnight-ntwrk/compact-runtime EC ops), which is exactly
|
|
14
|
+
// why signet.js does not cover it today.
|
|
15
|
+
import { randomBytes } from "node:crypto";
|
|
16
|
+
import { CompactTypeBytes, CompactTypeJubjubPoint, CompactTypeVector, ecMulGenerator, persistentHash, } from "@midnight-ntwrk/compact-runtime";
|
|
17
|
+
/** Jubjub curve scalar field order (group order of the generator). */
|
|
18
|
+
export const JUBJUB_ORDER = 6554484396890773809930967563523245729705921265872317281365359162392183254199n;
|
|
19
|
+
/** BLS12-381 scalar field order (the Compact `Field` type modulus). */
|
|
20
|
+
export const BLS_ORDER = 52435875175126190479447740508185965837690552500527637822603658699938581184513n;
|
|
21
|
+
const bytes32Type = new CompactTypeBytes(32);
|
|
22
|
+
const vec2x32Type = new CompactTypeVector(2, bytes32Type);
|
|
23
|
+
/**
|
|
24
|
+
* Convert little-endian bytes to a bigint. Matches Compact's
|
|
25
|
+
* `Bytes<32> as Field` interpretation (and the MPC monitor's ABI-word
|
|
26
|
+
* decoding convention).
|
|
27
|
+
*
|
|
28
|
+
* @param bytes - Little-endian byte array.
|
|
29
|
+
* @returns The decoded non-negative integer.
|
|
30
|
+
*/
|
|
31
|
+
export function bytesToBigint(bytes) {
|
|
32
|
+
let result = 0n;
|
|
33
|
+
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
34
|
+
result = (result << 8n) | BigInt(bytes[i]);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Convert a bigint to exactly 32 little-endian bytes. Matches Compact's
|
|
40
|
+
* `Field as Bytes<32>` encoding (the inverse of {@link bytesToBigint});
|
|
41
|
+
* negative inputs are interpreted in the BLS scalar field.
|
|
42
|
+
*
|
|
43
|
+
* @param n - The integer to encode.
|
|
44
|
+
* @returns The 32-byte little-endian encoding.
|
|
45
|
+
*/
|
|
46
|
+
export function bigintToBytes32(n) {
|
|
47
|
+
const buf = new Uint8Array(32);
|
|
48
|
+
let v = n < 0n ? n + BLS_ORDER : n;
|
|
49
|
+
for (let i = 0; i < 32; i++) {
|
|
50
|
+
buf[i] = Number(v & 0xffn);
|
|
51
|
+
v >>= 8n;
|
|
52
|
+
}
|
|
53
|
+
return buf;
|
|
54
|
+
}
|
|
55
|
+
/** Zero-pad an ASCII domain tag to 32 bytes (Compact `pad(32, ...)`). */
|
|
56
|
+
function pad32(tag) {
|
|
57
|
+
const padded = new Uint8Array(32);
|
|
58
|
+
new TextEncoder().encodeInto(tag, padded);
|
|
59
|
+
return padded;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Derive a Jubjub keypair from a seed — the same derivation the MPC server
|
|
63
|
+
* performs on its root key, so this MUST stay bit-identical to it:
|
|
64
|
+
* `sk = (persistentHash([pad32("jubjub:auth:"), seed]) mod (order - 1)) + 1`,
|
|
65
|
+
* `pk = sk * G`.
|
|
66
|
+
*
|
|
67
|
+
* @param seed - Seed bytes (e.g. the 32-byte MPC root key).
|
|
68
|
+
* @returns The derived {@link JubjubKeypair}.
|
|
69
|
+
*/
|
|
70
|
+
export function deriveJubjubKeypair(seed) {
|
|
71
|
+
const skBytes = persistentHash(vec2x32Type, [pad32("jubjub:auth:"), seed]);
|
|
72
|
+
const sk = (bytesToBigint(skBytes) % (JUBJUB_ORDER - 1n)) + 1n;
|
|
73
|
+
const pk = ecMulGenerator(sk);
|
|
74
|
+
return { sk, pk };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Sign a message with Schnorr on Jubjub, matching CompactStandardLibrary's
|
|
78
|
+
* `jubjubSchnorrVerify`: `c = challenge` (already reduced into Jubjub's
|
|
79
|
+
* scalar field by the compiled circuit), `s = (k + c * sk) mod JUBJUB_ORDER`.
|
|
80
|
+
* For signet attestations the message is the compiled
|
|
81
|
+
* `pureCircuits.signetAttestationMessage(requestId, outputData)`.
|
|
82
|
+
*
|
|
83
|
+
* @param sk - Jubjub private key scalar.
|
|
84
|
+
* @param msg - Message field limbs.
|
|
85
|
+
* @param schnorrChallenge - The compiled `pureCircuits.schnorrChallenge`.
|
|
86
|
+
* @returns The signature (announcement R, response s).
|
|
87
|
+
* @throws Error if `sk` reduces to zero mod the Jubjub order.
|
|
88
|
+
*/
|
|
89
|
+
export function schnorrSign(sk, msg, schnorrChallenge) {
|
|
90
|
+
const skReduced = ((sk % JUBJUB_ORDER) + JUBJUB_ORDER) % JUBJUB_ORDER;
|
|
91
|
+
if (skReduced === 0n) {
|
|
92
|
+
throw new Error("Private key must be non-zero mod JUBJUB_ORDER");
|
|
93
|
+
}
|
|
94
|
+
const pk = ecMulGenerator(skReduced);
|
|
95
|
+
const k = (bytesToBigint(randomBytes(32)) % JUBJUB_ORDER) || 1n;
|
|
96
|
+
const announcement = ecMulGenerator(k);
|
|
97
|
+
// schnorrChallenge returns the challenge already reduced into Jubjub's
|
|
98
|
+
// scalar field — use it as-is.
|
|
99
|
+
const c = schnorrChallenge(announcement.x, announcement.y, pk.x, pk.y, msg);
|
|
100
|
+
const response = (((k + c * skReduced) % JUBJUB_ORDER) + JUBJUB_ORDER) % JUBJUB_ORDER;
|
|
101
|
+
return { announcement, response };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Hash a Jubjub point exactly as the circuits do (`persistentHash<JubjubPoint>`)
|
|
105
|
+
* — the form the signet contract seals as `mpcPubKeyHash`.
|
|
106
|
+
*
|
|
107
|
+
* @param point - The point to hash.
|
|
108
|
+
* @returns The 32-byte hash.
|
|
109
|
+
*/
|
|
110
|
+
export function hashJubjubPoint(point) {
|
|
111
|
+
return persistentHash(CompactTypeJubjubPoint, point);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse a Jubjub public key from its `"x,y"` config/env form (decimal or
|
|
115
|
+
* 0x-hex field coordinates) — how deploys receive `MPC_JUBJUB_PK`.
|
|
116
|
+
*
|
|
117
|
+
* @param value - The `"x,y"` string.
|
|
118
|
+
* @returns The parsed point.
|
|
119
|
+
* @throws Error if the value is not two comma-separated field coordinates.
|
|
120
|
+
*/
|
|
121
|
+
export function parseJubjubPublicKey(value) {
|
|
122
|
+
const parts = value.split(",").map((part) => part.trim());
|
|
123
|
+
if (parts.length !== 2 || parts.some((part) => part === "")) {
|
|
124
|
+
throw new Error(`expected a Jubjub public key as "x,y"; got "${value}"`);
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
return { x: BigInt(parts[0]), y: BigInt(parts[1]) };
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new Error(`Jubjub public key coordinates must be decimal or 0x-hex integers; got "${value}"`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Format a Jubjub public key as the `"x,y"` decimal config/env form that
|
|
135
|
+
* {@link parseJubjubPublicKey} accepts — the round-trip inverse, for handing
|
|
136
|
+
* a derived key to deploys as `MPC_JUBJUB_PK`.
|
|
137
|
+
*
|
|
138
|
+
* @param point - The point to format.
|
|
139
|
+
* @returns The `"x,y"` string with decimal coordinates.
|
|
140
|
+
*/
|
|
141
|
+
export function formatJubjubPublicKey(point) {
|
|
142
|
+
return `${point.x},${point.y}`;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=schnorr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schnorr.js","sourceRoot":"","sources":["../src/schnorr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type RequestIdHex, type SignBidirectionalRequest, type SignBidirectionalRequestIndex } from "./signet-requests.ts";
|
|
2
|
+
import { type RawContractState } from "./signature-state-reading.ts";
|
|
3
|
+
/** Signet layout convention: the request index is ledger field 0. */
|
|
4
|
+
export declare const SIGNET_REQUESTS_INDEX_FIELD = 0;
|
|
5
|
+
/** Signet layout convention: the request counter (`SignetNonce`) is ledger field 1. */
|
|
6
|
+
export declare const SIGNET_NONCE_FIELD = 1;
|
|
7
|
+
/**
|
|
8
|
+
* Aligned-value entry count of a request record EXCLUDING the capacity-scaled
|
|
9
|
+
* vectors: requestNonce (1) + txParamType (1, enums are one atom whatever
|
|
10
|
+
* their byte width) + the EVMType2TxParams fixed fields (to..value = 7,
|
|
11
|
+
* accessListEntryCount = 1) + the calldata Maybe's is_some (1), selector (1)
|
|
12
|
+
* and noWords (1) + the routing fields caip2Id..respondSerializationSchema (8).
|
|
13
|
+
* A stored request cell therefore holds
|
|
14
|
+
* `REQUEST_FIXED_VALUE_ATOMS + maxCalldataWords
|
|
15
|
+
* + maxAccessListEntries·(2 + maxStorageKeysPerEntry)`
|
|
16
|
+
* entries (each calldata word is one Bytes<32> atom; each access-list entry is
|
|
17
|
+
* address + storageKeyCount + its keys).
|
|
18
|
+
*/
|
|
19
|
+
export declare const REQUEST_FIXED_VALUE_ATOMS = 21;
|
|
20
|
+
/**
|
|
21
|
+
* The decoded signet ledger fields of a conforming contract — the complete
|
|
22
|
+
* view the MPC needs: the request index (field 0) and the request counter
|
|
23
|
+
* (field 1, Compact `SignetNonce`), whose value doubles as a cheap
|
|
24
|
+
* change-detection signal (unchanged nonce ⇒ no new requests).
|
|
25
|
+
*/
|
|
26
|
+
export interface SignetRequestsLedger {
|
|
27
|
+
/** The request counter (ledger field {@link SIGNET_NONCE_FIELD}). */
|
|
28
|
+
nonce: bigint;
|
|
29
|
+
/**
|
|
30
|
+
* The request index (ledger field {@link SIGNET_REQUESTS_INDEX_FIELD}),
|
|
31
|
+
* keyed by hex request id.
|
|
32
|
+
*/
|
|
33
|
+
requestsIndex: SignBidirectionalRequestIndex;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* MPC-style read: parse the signet ledger fields out of raw contract state
|
|
37
|
+
* by field position alone — no compiled contract, no generated `ledger()`,
|
|
38
|
+
* only the signet layout convention and the canonical descriptors from
|
|
39
|
+
* signet-requests.ts.
|
|
40
|
+
*
|
|
41
|
+
* @param raw - Raw contract state, e.g. `queryContractState(address).data`
|
|
42
|
+
* from the indexer or `ctx.currentQueryContext.state` from the simulator.
|
|
43
|
+
* @returns The decoded {@link SignetRequestsLedger}.
|
|
44
|
+
* @throws Error if a field is missing, has the wrong state-value shape, or a
|
|
45
|
+
* record matches no capacity split.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readSignetRequestsLedgerFromState(raw: RawContractState): SignetRequestsLedger;
|
|
48
|
+
/**
|
|
49
|
+
* Look up ONE request by id in a contract's request index at an arbitrary
|
|
50
|
+
* ledger field — the generalization of {@link readSignetRequestsLedgerFromState}
|
|
51
|
+
* the event path needs: a `SignBidirectionalEvent` names both the requester
|
|
52
|
+
* contract AND which field holds its index, so the field is no longer assumed
|
|
53
|
+
* to be {@link SIGNET_REQUESTS_INDEX_FIELD}.
|
|
54
|
+
*
|
|
55
|
+
* This is the mandatory membership check of the event flow (see
|
|
56
|
+
* signet-request-resolver.ts): `undefined` means the id is NOT a member of the
|
|
57
|
+
* index at `fieldIndex` — the notification is forged, stale, points at the
|
|
58
|
+
* wrong field, or the request is not yet indexed — and the caller MUST drop it.
|
|
59
|
+
* Every non-membership case (field out of range, field is not a Map, id absent,
|
|
60
|
+
* a cell that fails to decode) returns `undefined` rather than throwing, so a
|
|
61
|
+
* malformed or adversarial event can never crash the reader.
|
|
62
|
+
*
|
|
63
|
+
* Only the matched record is decoded (not the whole index), and it is decoded
|
|
64
|
+
* by the same {@link decodeSignBidirectionalRequest} the full reader uses, so
|
|
65
|
+
* the result is `toEqual` to `readSignetRequestsLedgerFromState(raw)
|
|
66
|
+
* .requestsIndex.get(requestId)` when `fieldIndex` is the index field.
|
|
67
|
+
*
|
|
68
|
+
* @param raw - Raw contract state, e.g. `queryContractState(address).data`.
|
|
69
|
+
* @param fieldIndex - Ledger field position of the request index in `raw`.
|
|
70
|
+
* @param requestId - The request id to look up.
|
|
71
|
+
* @returns The stored request record, or `undefined` when it is not a member.
|
|
72
|
+
*/
|
|
73
|
+
export declare function lookupSignetRequestAt(raw: RawContractState, fieldIndex: number, requestId: RequestIdHex): SignBidirectionalRequest | undefined;
|
|
74
|
+
//# sourceMappingURL=signature-requests-state-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-requests-state-reader.d.ts","sourceRoot":"","sources":["../src/signature-requests-state-reader.ts"],"names":[],"mappings":"AAaA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EACnC,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAEtC,qEAAqE;AACrE,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AA+D5C;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,EAAE,6BAA6B,CAAC;CAC9C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,gBAAgB,GAAG,oBAAoB,CAwB7F;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,gBAAgB,EACrB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,YAAY,GACtB,wBAAwB,GAAG,SAAS,CA2BtC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// MPC-style raw state reader for the signature-REQUESTS side: decode the signet
|
|
2
|
+
// request ledger fields out of a contract's raw state WITHOUT the compiled
|
|
3
|
+
// contract. This is how the MPC monitor consumes signet contracts — it has only
|
|
4
|
+
// a contract address, queries raw state from the indexer
|
|
5
|
+
// (queryContractState(address).data), and decodes by the signet layout
|
|
6
|
+
// convention: the request index is ledger field 0, the request counter field 1.
|
|
7
|
+
// The compiled contract's generated ledger() does exactly this walk internally;
|
|
8
|
+
// the record descriptors themselves are the parameterized twins in
|
|
9
|
+
// signet-requests.ts. The generic tree walk and shared base descriptors live
|
|
10
|
+
// in signature-state-reading.ts.
|
|
11
|
+
import { requestIdHex, signBidirectionalRequestDescriptor, } from "./signet-requests.js";
|
|
12
|
+
import { requestIdType, signetFieldNode, u64, } from "./signature-state-reading.js";
|
|
13
|
+
/** Signet layout convention: the request index is ledger field 0. */
|
|
14
|
+
export const SIGNET_REQUESTS_INDEX_FIELD = 0;
|
|
15
|
+
/** Signet layout convention: the request counter (`SignetNonce`) is ledger field 1. */
|
|
16
|
+
export const SIGNET_NONCE_FIELD = 1;
|
|
17
|
+
/**
|
|
18
|
+
* Aligned-value entry count of a request record EXCLUDING the capacity-scaled
|
|
19
|
+
* vectors: requestNonce (1) + txParamType (1, enums are one atom whatever
|
|
20
|
+
* their byte width) + the EVMType2TxParams fixed fields (to..value = 7,
|
|
21
|
+
* accessListEntryCount = 1) + the calldata Maybe's is_some (1), selector (1)
|
|
22
|
+
* and noWords (1) + the routing fields caip2Id..respondSerializationSchema (8).
|
|
23
|
+
* A stored request cell therefore holds
|
|
24
|
+
* `REQUEST_FIXED_VALUE_ATOMS + maxCalldataWords
|
|
25
|
+
* + maxAccessListEntries·(2 + maxStorageKeysPerEntry)`
|
|
26
|
+
* entries (each calldata word is one Bytes<32> atom; each access-list entry is
|
|
27
|
+
* address + storageKeyCount + its keys).
|
|
28
|
+
*/
|
|
29
|
+
export const REQUEST_FIXED_VALUE_ATOMS = 21;
|
|
30
|
+
/**
|
|
31
|
+
* Recover a record's capacity instantiation (maxCalldataWords,
|
|
32
|
+
* maxAccessListEntries, maxStorageKeysPerEntry) from its aligned-value atom
|
|
33
|
+
* count and decode it. Unlike the old single-vector layout, one atom count no
|
|
34
|
+
* longer determines the capacities uniquely, so candidates are enumerated —
|
|
35
|
+
* access-list-free first (today's only producer, the vault, is <2, 0, 0>) —
|
|
36
|
+
* and validated by the decode itself: the descriptors' Bytes length checks
|
|
37
|
+
* and the enum range check reject wrong splits, and a decode that leaves
|
|
38
|
+
* atoms unconsumed is rejected here.
|
|
39
|
+
*
|
|
40
|
+
* @param atoms - The record cell's aligned value (a fresh copy per attempt).
|
|
41
|
+
* @returns The decoded record.
|
|
42
|
+
* @throws Error if no capacity split decodes the value cleanly.
|
|
43
|
+
*/
|
|
44
|
+
function decodeSignBidirectionalRequest(atoms) {
|
|
45
|
+
const variable = atoms.length - REQUEST_FIXED_VALUE_ATOMS;
|
|
46
|
+
if (variable < 0) {
|
|
47
|
+
throw new Error(`request record has ${atoms.length} value entries — fewer than the ` +
|
|
48
|
+
`${REQUEST_FIXED_VALUE_ATOMS} its fixed fields need`);
|
|
49
|
+
}
|
|
50
|
+
const attempt = (maxWords, maxEntries, maxKeys) => {
|
|
51
|
+
const cursor = [...atoms];
|
|
52
|
+
try {
|
|
53
|
+
const record = signBidirectionalRequestDescriptor(maxWords, maxEntries, maxKeys).fromValue(cursor);
|
|
54
|
+
// A clean decode consumes the record exactly.
|
|
55
|
+
return cursor.length === 0 ? record : undefined;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// No access list: variable atoms are calldata words alone (one atom each).
|
|
62
|
+
{
|
|
63
|
+
const record = attempt(variable, 0, 0);
|
|
64
|
+
if (record !== undefined)
|
|
65
|
+
return record;
|
|
66
|
+
}
|
|
67
|
+
// With an access list: E entries of (2 + K) atoms, the rest words.
|
|
68
|
+
for (let entries = 1; entries * 2 <= variable; entries++) {
|
|
69
|
+
for (let keys = 0; entries * (2 + keys) <= variable; keys++) {
|
|
70
|
+
const words = variable - entries * (2 + keys);
|
|
71
|
+
const record = attempt(words, entries, keys);
|
|
72
|
+
if (record !== undefined)
|
|
73
|
+
return record;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`request record with ${atoms.length} value entries matches no ` +
|
|
77
|
+
`(calldata words, access-list entries, storage keys) capacity split`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* MPC-style read: parse the signet ledger fields out of raw contract state
|
|
81
|
+
* by field position alone — no compiled contract, no generated `ledger()`,
|
|
82
|
+
* only the signet layout convention and the canonical descriptors from
|
|
83
|
+
* signet-requests.ts.
|
|
84
|
+
*
|
|
85
|
+
* @param raw - Raw contract state, e.g. `queryContractState(address).data`
|
|
86
|
+
* from the indexer or `ctx.currentQueryContext.state` from the simulator.
|
|
87
|
+
* @returns The decoded {@link SignetRequestsLedger}.
|
|
88
|
+
* @throws Error if a field is missing, has the wrong state-value shape, or a
|
|
89
|
+
* record matches no capacity split.
|
|
90
|
+
*/
|
|
91
|
+
export function readSignetRequestsLedgerFromState(raw) {
|
|
92
|
+
const map = signetFieldNode(raw, SIGNET_REQUESTS_INDEX_FIELD).asMap();
|
|
93
|
+
if (map === undefined) {
|
|
94
|
+
throw new Error(`Ledger field ${SIGNET_REQUESTS_INDEX_FIELD} is not a Map`);
|
|
95
|
+
}
|
|
96
|
+
const requestsIndex = new Map();
|
|
97
|
+
for (const key of map.keys()) {
|
|
98
|
+
// fromValue consumes its input, so hand each descriptor a copy.
|
|
99
|
+
const requestId = requestIdType.fromValue([...key.value]);
|
|
100
|
+
const cell = map.get(key)?.asCell();
|
|
101
|
+
if (cell === undefined)
|
|
102
|
+
continue;
|
|
103
|
+
requestsIndex.set(requestIdHex(requestId), decodeSignBidirectionalRequest(cell.value));
|
|
104
|
+
}
|
|
105
|
+
const nonceCell = signetFieldNode(raw, SIGNET_NONCE_FIELD).asCell();
|
|
106
|
+
if (nonceCell === undefined) {
|
|
107
|
+
throw new Error(`Ledger field ${SIGNET_NONCE_FIELD} is not a Cell`);
|
|
108
|
+
}
|
|
109
|
+
const nonce = u64.fromValue([...nonceCell.value]);
|
|
110
|
+
return { nonce, requestsIndex };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Look up ONE request by id in a contract's request index at an arbitrary
|
|
114
|
+
* ledger field — the generalization of {@link readSignetRequestsLedgerFromState}
|
|
115
|
+
* the event path needs: a `SignBidirectionalEvent` names both the requester
|
|
116
|
+
* contract AND which field holds its index, so the field is no longer assumed
|
|
117
|
+
* to be {@link SIGNET_REQUESTS_INDEX_FIELD}.
|
|
118
|
+
*
|
|
119
|
+
* This is the mandatory membership check of the event flow (see
|
|
120
|
+
* signet-request-resolver.ts): `undefined` means the id is NOT a member of the
|
|
121
|
+
* index at `fieldIndex` — the notification is forged, stale, points at the
|
|
122
|
+
* wrong field, or the request is not yet indexed — and the caller MUST drop it.
|
|
123
|
+
* Every non-membership case (field out of range, field is not a Map, id absent,
|
|
124
|
+
* a cell that fails to decode) returns `undefined` rather than throwing, so a
|
|
125
|
+
* malformed or adversarial event can never crash the reader.
|
|
126
|
+
*
|
|
127
|
+
* Only the matched record is decoded (not the whole index), and it is decoded
|
|
128
|
+
* by the same {@link decodeSignBidirectionalRequest} the full reader uses, so
|
|
129
|
+
* the result is `toEqual` to `readSignetRequestsLedgerFromState(raw)
|
|
130
|
+
* .requestsIndex.get(requestId)` when `fieldIndex` is the index field.
|
|
131
|
+
*
|
|
132
|
+
* @param raw - Raw contract state, e.g. `queryContractState(address).data`.
|
|
133
|
+
* @param fieldIndex - Ledger field position of the request index in `raw`.
|
|
134
|
+
* @param requestId - The request id to look up.
|
|
135
|
+
* @returns The stored request record, or `undefined` when it is not a member.
|
|
136
|
+
*/
|
|
137
|
+
export function lookupSignetRequestAt(raw, fieldIndex, requestId) {
|
|
138
|
+
let node;
|
|
139
|
+
try {
|
|
140
|
+
node = signetFieldNode(raw, fieldIndex);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return undefined; // field position out of range for this contract
|
|
144
|
+
}
|
|
145
|
+
const map = node.asMap();
|
|
146
|
+
if (map === undefined) {
|
|
147
|
+
return undefined; // the named field is not a request index
|
|
148
|
+
}
|
|
149
|
+
for (const key of map.keys()) {
|
|
150
|
+
// fromValue consumes its input, so hand each descriptor a copy.
|
|
151
|
+
if (requestIdHex(requestIdType.fromValue([...key.value])) !== requestId) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const cell = map.get(key)?.asCell();
|
|
155
|
+
if (cell === undefined) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
return decodeSignBidirectionalRequest(cell.value);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return undefined; // a cell that is not a decodable request record
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return undefined; // id absent from the index
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=signature-requests-state-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-requests-state-reader.js","sourceRoot":"","sources":["../src/signature-requests-state-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type SignBidirectionalRequest } from "./signet-requests.ts";
|
|
2
|
+
import type { SignatureResponse } from "./signet-contract-state-reader.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Recover the EVM address that produced a response signature, over the
|
|
5
|
+
* signing hash of the transaction the request describes.
|
|
6
|
+
*
|
|
7
|
+
* @param request - The on-ledger request record the response answers.
|
|
8
|
+
* @param response - The posted signature record answering it.
|
|
9
|
+
* @returns The checksummed recovered signer address.
|
|
10
|
+
* @throws Error if the response is not a decodable signature or the request
|
|
11
|
+
* record is malformed (see
|
|
12
|
+
* {@link signBidirectionalRequestToUnsignedEVMTransaction}).
|
|
13
|
+
*/
|
|
14
|
+
export declare function recoverSignatureResponseSigner(request: SignBidirectionalRequest, response: SignatureResponse): string;
|
|
15
|
+
/**
|
|
16
|
+
* Verify a posted response against its request: does the signature recover
|
|
17
|
+
* to `expectedSigner`? Never throws — a response that is malformed or signed
|
|
18
|
+
* by anyone else is simply not valid, which is the expected state of affairs
|
|
19
|
+
* on an unauthenticated log.
|
|
20
|
+
*
|
|
21
|
+
* @param request - The on-ledger request record the response answers.
|
|
22
|
+
* @param response - The posted signature record answering it.
|
|
23
|
+
* @param expectedSigner - The EVM address (any case, 0x hex) that must have signed.
|
|
24
|
+
* @returns `true` iff the response is a valid signature by `expectedSigner`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function verifySignatureResponse(request: SignBidirectionalRequest, response: SignatureResponse, expectedSigner: string): boolean;
|
|
27
|
+
//# sourceMappingURL=signature-response-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-response-verification.d.ts","sourceRoot":"","sources":["../src/signature-response-verification.ts"],"names":[],"mappings":"AAWA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE3E;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,CAKR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,iBAAiB,EAC3B,cAAc,EAAE,MAAM,GACrB,OAAO,CAST"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Client-side verification of MPC signature responses. Posting to the
|
|
2
|
+
// signet contract's signature response log is UNAUTHENTICATED (see "Signet
|
|
3
|
+
// Layout" in Signet.compact), so a poller must verify every posted response
|
|
4
|
+
// before trusting it: rebuild the unsigned EVM transaction from the on-ledger
|
|
5
|
+
// request record — assembled exactly as the MPC assembles it (sig-net/mpc
|
|
6
|
+
// response server, managed/erc20-vault/signet/calldata-builder.ts) — and
|
|
7
|
+
// check that the posted `{ bigR, s, recoveryId }` signature recovers to the
|
|
8
|
+
// requester's derived EVM address over that transaction's signing hash.
|
|
9
|
+
import { getAddress, recoverAddress } from "ethers";
|
|
10
|
+
import { signBidirectionalRequestToUnsignedEVMTransaction, signatureResponseToSignature, } from "./signet-requests.js";
|
|
11
|
+
/**
|
|
12
|
+
* Recover the EVM address that produced a response signature, over the
|
|
13
|
+
* signing hash of the transaction the request describes.
|
|
14
|
+
*
|
|
15
|
+
* @param request - The on-ledger request record the response answers.
|
|
16
|
+
* @param response - The posted signature record answering it.
|
|
17
|
+
* @returns The checksummed recovered signer address.
|
|
18
|
+
* @throws Error if the response is not a decodable signature or the request
|
|
19
|
+
* record is malformed (see
|
|
20
|
+
* {@link signBidirectionalRequestToUnsignedEVMTransaction}).
|
|
21
|
+
*/
|
|
22
|
+
export function recoverSignatureResponseSigner(request, response) {
|
|
23
|
+
return recoverAddress(signBidirectionalRequestToUnsignedEVMTransaction(request).unsignedHash, signatureResponseToSignature(response));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Verify a posted response against its request: does the signature recover
|
|
27
|
+
* to `expectedSigner`? Never throws — a response that is malformed or signed
|
|
28
|
+
* by anyone else is simply not valid, which is the expected state of affairs
|
|
29
|
+
* on an unauthenticated log.
|
|
30
|
+
*
|
|
31
|
+
* @param request - The on-ledger request record the response answers.
|
|
32
|
+
* @param response - The posted signature record answering it.
|
|
33
|
+
* @param expectedSigner - The EVM address (any case, 0x hex) that must have signed.
|
|
34
|
+
* @returns `true` iff the response is a valid signature by `expectedSigner`.
|
|
35
|
+
*/
|
|
36
|
+
export function verifySignatureResponse(request, response, expectedSigner) {
|
|
37
|
+
try {
|
|
38
|
+
return (recoverSignatureResponseSigner(request, response) ===
|
|
39
|
+
getAddress(expectedSigner));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=signature-response-verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-response-verification.js","sourceRoot":"","sources":["../src/signature-response-verification.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAEpD,OAAO,EACL,gDAAgD,EAChD,4BAA4B,GAE7B,MAAM,sBAAsB,CAAC;AAG9B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,8BAA8B,CAC5C,OAAiC,EACjC,QAA2B;IAE3B,OAAO,cAAc,CACnB,gDAAgD,CAAC,OAAO,CAAC,CAAC,YAAY,EACtE,4BAA4B,CAAC,QAAQ,CAAC,CACvC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAiC,EACjC,QAA2B,EAC3B,cAAsB;IAEtB,IAAI,CAAC;QACH,OAAO,CACL,8BAA8B,CAAC,OAAO,EAAE,QAAQ,CAAC;YACjD,UAAU,CAAC,cAAc,CAAC,CAC3B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CompactTypeBytes, CompactTypeUnsignedInteger, type CompactType, type StateValue } from "@midnight-ntwrk/compact-runtime";
|
|
2
|
+
import { type RequestId } from "./signet-requests.ts";
|
|
3
|
+
/** Descriptor for a Compact `Uint<64>` (8-byte unsigned integer). */
|
|
4
|
+
export declare const u64: CompactTypeUnsignedInteger;
|
|
5
|
+
/** Descriptor for a Compact `Bytes<32>`. */
|
|
6
|
+
export declare const bytes32: CompactTypeBytes;
|
|
7
|
+
/**
|
|
8
|
+
* Descriptor for a request id ledger key (Compact `RequestId`, a
|
|
9
|
+
* nominal `Bytes<32>`). Use it to encode a {@link RequestId} into the
|
|
10
|
+
* aligned form the state tree stores, or decode one back.
|
|
11
|
+
*/
|
|
12
|
+
export declare const requestIdType: CompactType<RequestId>;
|
|
13
|
+
/**
|
|
14
|
+
* What the indexer / simulator hands us: a bare `StateValue`, or anything
|
|
15
|
+
* wrapping one under `.state` (e.g. `ChargedState`,
|
|
16
|
+
* `queryContractState(address).data`).
|
|
17
|
+
*/
|
|
18
|
+
export type RawContractState = StateValue | {
|
|
19
|
+
state: StateValue;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a flat ledger field index to its node in the raw state tree.
|
|
23
|
+
*
|
|
24
|
+
* The runtime stores ledger fields as a root array and chunks them one level
|
|
25
|
+
* deep once the field count grows, so chunked roots are flattened before
|
|
26
|
+
* indexing. Chunk detection assumes signet field 0 is a `Map`, never a
|
|
27
|
+
* `List` (whose node is also array-typed) — guaranteed by the signet layout
|
|
28
|
+
* convention.
|
|
29
|
+
*
|
|
30
|
+
* @param raw - Raw contract state from the indexer or simulator.
|
|
31
|
+
* @param flatIndex - Zero-based ledger field position in declaration order.
|
|
32
|
+
* @returns The `StateValue` node holding that field.
|
|
33
|
+
* @throws Error if `flatIndex` is beyond the contract's field count.
|
|
34
|
+
*/
|
|
35
|
+
export declare function signetFieldNode(raw: RawContractState, flatIndex: number): StateValue;
|
|
36
|
+
//# sourceMappingURL=signature-state-reading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature-state-reading.d.ts","sourceRoot":"","sources":["../src/signature-state-reading.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAOtD,qEAAqE;AACrE,eAAO,MAAM,GAAG,4BAA2D,CAAC;AAE5E,4CAA4C;AAC5C,eAAO,MAAM,OAAO,kBAA2B,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,SAAS,CAAW,CAAC;AAI7D;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAWlE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,GAChB,UAAU,CAgBZ"}
|