@sig-net/midnight 0.24.0 → 0.25.0-rc.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 +9 -8
- package/dist/abi-serde.d.ts +7 -5
- package/dist/abi-serde.d.ts.map +1 -1
- package/dist/abi-serde.js +9 -6
- package/dist/abi-serde.js.map +1 -1
- package/dist/compact-descriptors.d.ts +5 -7
- package/dist/compact-descriptors.d.ts.map +1 -1
- package/dist/compact-descriptors.js +7 -19
- package/dist/compact-descriptors.js.map +1 -1
- package/dist/constants.d.ts +7 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -4
- package/dist/constants.js.map +1 -1
- package/dist/ecdsa-attestation.d.ts +61 -12
- package/dist/ecdsa-attestation.d.ts.map +1 -1
- package/dist/ecdsa-attestation.js +92 -39
- package/dist/ecdsa-attestation.js.map +1 -1
- package/dist/epsilon-derivation.d.ts +9 -7
- package/dist/epsilon-derivation.d.ts.map +1 -1
- package/dist/epsilon-derivation.js +6 -5
- package/dist/epsilon-derivation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/managed/compiler/contract-info.json +251 -143
- package/dist/managed/compiler/contract-manifest.json +8 -8
- package/dist/managed/contract/index.d.ts +75 -46
- package/dist/managed/contract/index.js +604 -585
- package/dist/managed/contract/index.js.map +1 -1
- package/dist/mpc-output-cache.d.ts +7 -5
- package/dist/mpc-output-cache.d.ts.map +1 -1
- package/dist/mpc-output-cache.js +6 -5
- package/dist/mpc-output-cache.js.map +1 -1
- package/dist/signet-contract-events.d.ts +20 -11
- package/dist/signet-contract-events.d.ts.map +1 -1
- package/dist/signet-contract-events.js +9 -6
- package/dist/signet-contract-events.js.map +1 -1
- package/dist/signet-evtype2tx-record-decoding.js +2 -2
- package/dist/signet-evtype2tx-requests.d.ts +3 -5
- package/dist/signet-evtype2tx-requests.d.ts.map +1 -1
- package/dist/signet-evtype2tx-requests.js +2 -4
- package/dist/signet-evtype2tx-requests.js.map +1 -1
- package/dist/signet-requests.d.ts +7 -6
- package/dist/signet-requests.d.ts.map +1 -1
- package/dist/signet-requests.js +2 -2
- package/dist/signet-requests.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/src/Signet.compact +138 -70
- package/src/circuits.compact +40 -32
package/src/Signet.compact
CHANGED
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
// - SignBidirectionalEventNotification: the notification delivered through that call, versioned by
|
|
27
27
|
// the version byte it carries.
|
|
28
28
|
// - SignatureRespondedEventV1: the MPC's posted signature answering a request.
|
|
29
|
-
// - RespondBidirectionalEventV1: the MPC's posted attestation
|
|
30
|
-
//
|
|
29
|
+
// - RespondBidirectionalEventV1: the MPC's posted attestation of the signed transaction's outcome
|
|
30
|
+
// (executed, failed or unviable).
|
|
31
31
|
//
|
|
32
32
|
// The V1 suffix marks the wire and hash-domain artefacts of protocol version 1 (the structs the
|
|
33
|
-
// ledger stores and the singleton emits, and the circuits that hash or
|
|
34
|
-
// shared across versions (RequestId, OutputKind, Signature, the enums, the transaction
|
|
35
|
-
// structs, which TxParamType tags) and the version-tagged notification carry no suffix.
|
|
33
|
+
// ledger stores and the singleton emits, and the circuits that hash, verify or construct them).
|
|
34
|
+
// Vocabulary shared across versions (RequestId, OutputKind, Signature, the enums, the transaction
|
|
35
|
+
// parameter structs, which TxParamType tags) and the version-tagged notification carry no suffix.
|
|
36
36
|
//
|
|
37
37
|
// These key types are best understood within the sign bidirectional flow that they enable:
|
|
38
38
|
// 1. Client contract stores a SignBidirectionalEvent in a SignBidirectionalEventMap in its own ledger
|
|
@@ -45,18 +45,21 @@
|
|
|
45
45
|
// signature) through the Signet singleton, which emits it as a contract event.
|
|
46
46
|
// 3. Client polls the Signet singleton contract's SignatureRespondedEvent events, identifying the response
|
|
47
47
|
// associated with their request by RequestId. Clients validate the signature is correct by checking with
|
|
48
|
-
// the requested signing key. Then it broadcasts the signed txn to the
|
|
49
|
-
// 4. MPC observes txn
|
|
50
|
-
//
|
|
48
|
+
// the requested signing key. Then it broadcasts the signed txn to the target chain.
|
|
49
|
+
// 4. MPC observes the txn's outcome in a final block on the target chain (executed, failed,
|
|
50
|
+
// or unviable when another request's transaction took its nonce) and posts a
|
|
51
|
+
// RespondBidirectionalEvent attestation through the Signet singleton, which emits it as a
|
|
52
|
+
// contract event beside the request id.
|
|
51
53
|
// The client polls its request's posts and takes the first one that verifies over the request id,
|
|
52
54
|
// block height, output kind and output. The client obtains the execution output off chain (for EVM: the mined
|
|
53
|
-
// call's return data via debug_traceTransaction,
|
|
54
|
-
// MPC's output cache) and hands
|
|
55
|
-
//
|
|
55
|
+
// call's return data via debug_traceTransaction, re-serialised exactly as the MPC did with
|
|
56
|
+
// executedEvmRespondOutput, or the exact attested bytes from the MPC's output cache) and hands the
|
|
57
|
+
// serialised output plus attestation to its verify circuit. See
|
|
58
|
+
// "Output Recovery and Serialisation" in the repository README.
|
|
56
59
|
//
|
|
57
60
|
// Read more:
|
|
58
|
-
// - The sign bidirectional flow and key derivation:
|
|
59
|
-
// ("Sign
|
|
61
|
+
// - The sign bidirectional flow and key derivation: the repository README
|
|
62
|
+
// ("Sign Bidirectional Protocol Flow", "Derived Keys").
|
|
60
63
|
// - For full integration examples (such as an ERC20 cross chain vault example) see
|
|
61
64
|
// the Midnight Examples repository at: https://github.com/sig-net/midnight-examples.
|
|
62
65
|
// - Compact language reference (modules, types):
|
|
@@ -73,6 +76,7 @@ module Signet {
|
|
|
73
76
|
evmType2TxWord,
|
|
74
77
|
evmType2TxAccessEntry,
|
|
75
78
|
evmType2TxStorageKey,
|
|
79
|
+
attestedOutput,
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
// ---- SignBidirectionalEvent ------------------------------------------------------------------------
|
|
@@ -92,7 +96,8 @@ module Signet {
|
|
|
92
96
|
// variant for requests made from Midnight contracts), not this record's target
|
|
93
97
|
// executionDest. The path is 32 opaque bytes of the client contract's choosing (e.g. a
|
|
94
98
|
// fixed literal for a contract-owned account or a hash of a caller's secret for
|
|
95
|
-
// per-user accounts): no format is enforced, any 32 bytes are valid
|
|
99
|
+
// per-user accounts): no format is enforced, and any 32 bytes are valid except
|
|
100
|
+
// pad(32, "midnight response key"), which is reserved for the MPC response key and refused.
|
|
96
101
|
// CRITICAL: the MPC renders the path as hex::encode(path) for key derivation (lowercase hex
|
|
97
102
|
// of the full 32 bytes, no trimming, no 0x prefix). The sender is always part
|
|
98
103
|
// of the derivation, so no contract can reach another contract's derived keys.
|
|
@@ -104,11 +109,12 @@ module Signet {
|
|
|
104
109
|
// MPC Parameters.
|
|
105
110
|
algo: MPCSignatureAlgorithm; // Signature algorithm scheme, e.g. ecdsa
|
|
106
111
|
|
|
107
|
-
//
|
|
112
|
+
// Target chain transaction parameters.
|
|
108
113
|
txParamType: TxParamType; // Off-chain tag indicating what type txParams is set to.
|
|
109
114
|
txParams: TxParams; // The generic transaction-param payload
|
|
110
|
-
executionDest: Bytes<
|
|
111
|
-
// (https://chainagnostic.org/CAIPs/caip-2)
|
|
115
|
+
executionDest: Bytes<64>; // The MPC's routing key for the target chain, in CAIP-2 form
|
|
116
|
+
// (https://chainagnostic.org/CAIPs/caip-2), zero-padded: 64 bytes
|
|
117
|
+
// hold any CAIP-2 id (at most 41). An Ethereum target
|
|
112
118
|
// (mainnet, Sepolia or a local anvil) uses ethereumCaip2Id():
|
|
113
119
|
// the network itself is txParams' chainId.
|
|
114
120
|
|
|
@@ -119,8 +125,8 @@ module Signet {
|
|
|
119
125
|
|
|
120
126
|
// ---- Serialisation Schemas ----
|
|
121
127
|
|
|
122
|
-
// outputDeserializationSchema tells the MPC how to decode the
|
|
123
|
-
// execution output (
|
|
128
|
+
// outputDeserializationSchema tells the MPC how to decode the target chain's
|
|
129
|
+
// execution output (target chain -> MPC).
|
|
124
130
|
// The value is execution chain specific and sized per client contract:
|
|
125
131
|
// - Ethereum: an ABI JSON schema string (see https://docs.soliditylang.org/en/v0.8.30/abi-spec.html#json)
|
|
126
132
|
// in canonical form: `[{"name":"<identifier>","type":"<abi type>"},...]` with no
|
|
@@ -165,7 +171,7 @@ module Signet {
|
|
|
165
171
|
algo: MPCSignatureAlgorithm,
|
|
166
172
|
txParamType: TxParamType,
|
|
167
173
|
txParams: TxParams,
|
|
168
|
-
executionDest: Bytes<
|
|
174
|
+
executionDest: Bytes<64>,
|
|
169
175
|
signatureDest: MPCDestination,
|
|
170
176
|
params: Bytes<64>,
|
|
171
177
|
outputDeserializationSchema: Bytes<LenOutputDeserialization>,
|
|
@@ -217,7 +223,7 @@ module Signet {
|
|
|
217
223
|
algo: MPCSignatureAlgorithm;
|
|
218
224
|
txParamType: TxParamType;
|
|
219
225
|
txParamsDigest: Bytes<32>;
|
|
220
|
-
executionDest: Bytes<
|
|
226
|
+
executionDest: Bytes<64>;
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
// Off-chain recomputation must prefix the preimage with HashDomain.requestId
|
|
@@ -329,7 +335,8 @@ module Signet {
|
|
|
329
335
|
// RespondBidirectionalEvent: the MPC's attestation of a foreign execution, the
|
|
330
336
|
// final step of the sign bidirectional flow.
|
|
331
337
|
//
|
|
332
|
-
//
|
|
338
|
+
// outputHash = calculateAttestedOutputHashV1(serializedOutput)
|
|
339
|
+
// attestationDigest = calculateSignetAttestationDigestV1(requestId, blockHeight, outputKind, serializedOutputLength, outputHash)
|
|
333
340
|
// signature = signSECP256k1(mpcResponseKey, attestationDigest)
|
|
334
341
|
//
|
|
335
342
|
// mpcResponseKey is derived like request signing keys, with the path set to the
|
|
@@ -337,28 +344,34 @@ module Signet {
|
|
|
337
344
|
// verbatim, unlike a request's hex-encoded 32 path bytes):
|
|
338
345
|
// mpcResponseKey = f(mpcRootKey[keyVersion], caip2ChainId, sender, "midnight response key")
|
|
339
346
|
//
|
|
340
|
-
// The output travels off chain
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
347
|
+
// The output travels off chain. The event carries everything the digest is
|
|
348
|
+
// computed from, so its signature checks without the output
|
|
349
|
+
// (verifyRespondBidirectionalAttestationV1), and the output checks against the
|
|
350
|
+
// event's length and hash (verifyAttestedOutputV1). The signature
|
|
351
|
+
// is the ONLY thing that distinguishes a genuine post from garbage: the
|
|
352
|
+
// singleton emits every post unverified.
|
|
344
353
|
export struct RespondBidirectionalEventV1 {
|
|
345
354
|
// The request this attestation answers. Signed into the digest: a verified
|
|
346
355
|
// post settles exactly the request it names, so a client consumes this id
|
|
347
356
|
// and never one taken from elsewhere.
|
|
348
357
|
requestId: RequestId;
|
|
349
|
-
// Height of the finalised
|
|
350
|
-
// attestation describes, in the
|
|
358
|
+
// Height of the finalised target-chain block holding the transaction the
|
|
359
|
+
// attestation describes, in the target chain's own numbering (a slot
|
|
351
360
|
// on Solana). Signed into the digest.
|
|
352
361
|
blockHeight: Uint<64>;
|
|
353
362
|
// The MPC's verdict on the execution, signed into the digest.
|
|
354
363
|
outputKind: OutputKind;
|
|
355
|
-
// Byte width of the serialised output
|
|
356
|
-
//
|
|
357
|
-
// width
|
|
364
|
+
// Byte width of the serialised output (0 for a failed or unviable
|
|
365
|
+
// execution), signed into the digest. The output hash does not commit to
|
|
366
|
+
// the width, so this does: a verifier checks it against the width of the
|
|
367
|
+
// output it was handed.
|
|
358
368
|
serializedOutputLength: Uint<64>;
|
|
369
|
+
// calculateAttestedOutputHashV1 of the serialised output, signed into the
|
|
370
|
+
// digest.
|
|
371
|
+
outputHash: Bytes<32>;
|
|
359
372
|
// The attestation digest the signature is over (calculateSignetAttestationDigestV1),
|
|
360
|
-
//
|
|
361
|
-
//
|
|
373
|
+
// for off-chain readers. The verifying circuits recompute it from the
|
|
374
|
+
// fields above and never read this copy.
|
|
362
375
|
digest: Bytes<32>;
|
|
363
376
|
// The MPC's ECDSA signature over the attestation digest.
|
|
364
377
|
signature: Signature;
|
|
@@ -366,56 +379,71 @@ module Signet {
|
|
|
366
379
|
|
|
367
380
|
// OutputKind is the MPC's verdict on a request's execution, the kind half of
|
|
368
381
|
// the protocol's outcome (kind, data). The block height the attestation
|
|
369
|
-
// commits to is the finalised
|
|
382
|
+
// commits to is the finalised target-chain block that settled the verdict.
|
|
370
383
|
export enum OutputKind {
|
|
371
384
|
executed, // finalised and succeeded: the attested output is the decoded return data, Borsh-serialised by the MPC (empty when the call returns nothing)
|
|
372
385
|
failed, // finalised and reverted: the attested output is empty (Bytes<0>)
|
|
373
|
-
unviable, // a finalised transaction
|
|
386
|
+
unviable, // a finalised transaction of another request from the same account took the nonce: the attested output is empty (Bytes<0>)
|
|
374
387
|
}
|
|
375
388
|
|
|
376
|
-
// The 32-byte
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
// Off-chain code uses the
|
|
382
|
-
//
|
|
383
|
-
|
|
389
|
+
// The 32-byte hash of a serialised execution output that the attestation
|
|
390
|
+
// digest commits to:
|
|
391
|
+
// outputHash = upgradeFromTransient(transientHash([HashDomain.attestedOutput, serializedOutput]))
|
|
392
|
+
// The hash packs the bytes into field elements without their width, so
|
|
393
|
+
// outputs that differ only in trailing zero bytes hash alike: the width is
|
|
394
|
+
// committed separately, as serializedOutputLength. Off-chain code uses the
|
|
395
|
+
// TypeScript twin:
|
|
396
|
+
// import { calculateAttestedOutputHash } from "@sig-net/midnight";
|
|
397
|
+
export pure circuit calculateAttestedOutputHashV1<#serializedOutputLength>(
|
|
398
|
+
serializedOutput: Bytes<serializedOutputLength>,
|
|
399
|
+
): Bytes<32> {
|
|
400
|
+
return upgradeFromTransient(transientHash<[HashDomain, Bytes<serializedOutputLength>]>([HashDomain.attestedOutput, serializedOutput]));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// The 32-byte attestation digest the MPC signs:
|
|
404
|
+
// attestationDigest = upgradeFromTransient(transientHash([HashDomain.attestationDigest, requestId, blockHeight, outputKind, serializedOutputLength, outputHash]))
|
|
405
|
+
// blockHeight is the height of the finalised target-chain block holding the
|
|
406
|
+
// transaction the attestation describes, in the target chain's own
|
|
407
|
+
// numbering (a slot on Solana). Every input is fixed-width, so the digest of
|
|
408
|
+
// any output is computed by this one circuit.
|
|
409
|
+
export pure circuit calculateSignetAttestationDigestV1(
|
|
384
410
|
requestId: RequestId,
|
|
385
411
|
blockHeight: Uint<64>,
|
|
386
412
|
outputKind: OutputKind,
|
|
387
|
-
|
|
413
|
+
serializedOutputLength: Uint<64>,
|
|
414
|
+
outputHash: Bytes<32>,
|
|
388
415
|
): Bytes<32> {
|
|
389
|
-
return upgradeFromTransient(transientHash<[HashDomain, RequestId, Uint<64>, OutputKind, Uint<64>, Bytes<
|
|
416
|
+
return upgradeFromTransient(transientHash<[HashDomain, RequestId, Uint<64>, OutputKind, Uint<64>, Bytes<32>]>([HashDomain.attestationDigest, requestId, blockHeight, outputKind, serializedOutputLength, outputHash]));
|
|
390
417
|
}
|
|
391
418
|
|
|
392
|
-
// Verifies a RespondBidirectionalEvent against
|
|
393
|
-
//
|
|
394
|
-
// output kind, output length and
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
//
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
// first
|
|
409
|
-
|
|
410
|
-
|
|
419
|
+
// Verifies a RespondBidirectionalEvent's signature against the MPC response
|
|
420
|
+
// key, without the output: recomputes the digest from the event's request
|
|
421
|
+
// id, block height, output kind, output length and output hash. The event's
|
|
422
|
+
// digest field is never read. A true result proves the MPC attested this
|
|
423
|
+
// outcome for this request, and an output the event carries only as its
|
|
424
|
+
// length and hash: a client that consumes output bytes checks them against
|
|
425
|
+
// that length and hash with verifyAttestedOutputV1, or verifies with
|
|
426
|
+
// verifyRespondBidirectionalEventV1, which does both.
|
|
427
|
+
// The caller supplies the event record with signature.bigR.x and
|
|
428
|
+
// signature.s byte-reversed into LITTLE-endian: the scalar casts below read
|
|
429
|
+
// little-endian bytes, and the wire/ledger records are big-endian, so the
|
|
430
|
+
// reversal happens off-chain where it costs nothing (the TS SDK's
|
|
431
|
+
// respondBidirectionalEventToCircuitInput does it). A wrong byte order fails
|
|
432
|
+
// verification, never a false accept. The digest binds the event's
|
|
433
|
+
// requestId, so a client MUST consume that request and no other. An s that
|
|
434
|
+
// reduces to 0 mod the curve order aborts the circuit rather than returning
|
|
435
|
+
// false, so sift candidate posts off chain first
|
|
436
|
+
// (verifyRespondBidirectionalAttestation).
|
|
437
|
+
export pure circuit verifyRespondBidirectionalAttestationV1(
|
|
411
438
|
respondBidirectionalEvent: RespondBidirectionalEventV1,
|
|
412
439
|
mpcResponseKey: Secp256k1Point
|
|
413
440
|
): Boolean {
|
|
414
|
-
const digest = calculateSignetAttestationDigestV1
|
|
441
|
+
const digest = calculateSignetAttestationDigestV1(
|
|
415
442
|
respondBidirectionalEvent.requestId,
|
|
416
443
|
respondBidirectionalEvent.blockHeight,
|
|
417
444
|
respondBidirectionalEvent.outputKind,
|
|
418
|
-
|
|
445
|
+
respondBidirectionalEvent.serializedOutputLength,
|
|
446
|
+
respondBidirectionalEvent.outputHash,
|
|
419
447
|
);
|
|
420
448
|
|
|
421
449
|
return secp256k1EcdsaVerify(
|
|
@@ -428,17 +456,57 @@ module Signet {
|
|
|
428
456
|
);
|
|
429
457
|
}
|
|
430
458
|
|
|
459
|
+
// Whether serializedOutput is the output an attestation declares: its width
|
|
460
|
+
// is attestedOutputLength and its hash attestedOutputHash. Both checks are
|
|
461
|
+
// needed, as the hash alone does not commit to the width (see
|
|
462
|
+
// calculateAttestedOutputHashV1). Proves nothing about the attestation
|
|
463
|
+
// itself: the length and hash must come from a RespondBidirectionalEvent that
|
|
464
|
+
// passed verifyRespondBidirectionalAttestationV1, read from the event or
|
|
465
|
+
// from a copy the contract stored when it verified the event.
|
|
466
|
+
export pure circuit verifyAttestedOutputV1<#serializedOutputLength>(
|
|
467
|
+
serializedOutput: Bytes<serializedOutputLength>,
|
|
468
|
+
attestedOutputLength: Uint<64>,
|
|
469
|
+
attestedOutputHash: Bytes<32>
|
|
470
|
+
): Boolean {
|
|
471
|
+
const lengthMatches = attestedOutputLength == serializedOutputLength;
|
|
472
|
+
const hashMatches = attestedOutputHash == calculateAttestedOutputHashV1<serializedOutputLength>(serializedOutput);
|
|
473
|
+
return lengthMatches && hashMatches;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Verifies a RespondBidirectionalEvent against its execution output and MPC
|
|
477
|
+
// response key: the output is the one the event attests (verifyAttestedOutputV1
|
|
478
|
+
// against the event's length and hash) and the event's signature verifies
|
|
479
|
+
// (verifyRespondBidirectionalAttestationV1, whose byte-order and abort
|
|
480
|
+
// contract applies here too). Client contracts run this before consuming
|
|
481
|
+
// outputs, as the singleton emits responses unverified. The caller supplies
|
|
482
|
+
// serializedOutput at its exact unpadded width.
|
|
483
|
+
export pure circuit verifyRespondBidirectionalEventV1<#serializedOutputLength>(
|
|
484
|
+
serializedOutput: Bytes<serializedOutputLength>,
|
|
485
|
+
respondBidirectionalEvent: RespondBidirectionalEventV1,
|
|
486
|
+
mpcResponseKey: Secp256k1Point
|
|
487
|
+
): Boolean {
|
|
488
|
+
// Both checks run unconditionally: the signature check's scalar casts
|
|
489
|
+
// cannot sit in the short-circuited operand of &&.
|
|
490
|
+
const outputMatches = verifyAttestedOutputV1<serializedOutputLength>(
|
|
491
|
+
serializedOutput,
|
|
492
|
+
respondBidirectionalEvent.serializedOutputLength,
|
|
493
|
+
respondBidirectionalEvent.outputHash
|
|
494
|
+
);
|
|
495
|
+
const attested = verifyRespondBidirectionalAttestationV1(respondBidirectionalEvent, mpcResponseKey);
|
|
496
|
+
return outputMatches && attested;
|
|
497
|
+
}
|
|
498
|
+
|
|
431
499
|
// ---- EVM Type2 Transaction Parameters --------------------------------------------------------------
|
|
432
500
|
|
|
433
501
|
// The caip2Id of every request targeting Ethereum, whichever Ethereum network the
|
|
434
|
-
// MPC
|
|
502
|
+
// MPC deployment watches (mainnet, Sepolia or a local anvil: set per deployment).
|
|
435
503
|
// The MPC routes on this exact string (Chain::Ethereum in sig-net/mpc
|
|
436
504
|
// signet-primitives/src/chain.rs) and rejects the request for any other value,
|
|
437
505
|
// the network's own CAIP-2 id included. EvmType2TxParams.chainId is what binds
|
|
438
506
|
// the signed transaction to one network. Ethereum only: another EVM chain, such as
|
|
439
507
|
// BNB Smart Chain, is a separate chain to the MPC, never one of Ethereum's networks.
|
|
440
|
-
export pure circuit ethereumCaip2Id(): Bytes<
|
|
441
|
-
return pad(
|
|
508
|
+
export pure circuit ethereumCaip2Id(): Bytes<64> {
|
|
509
|
+
return pad(64, "eip155:1");
|
|
442
510
|
}
|
|
443
511
|
|
|
444
512
|
// The EVM transaction to be signed, decomposed into typed fields
|
|
@@ -462,7 +530,7 @@ module Signet {
|
|
|
462
530
|
maxPriorityFeePerGas: Uint<128>; // wei
|
|
463
531
|
maxFeePerGas: Uint<128>; // wei
|
|
464
532
|
gasLimit: Uint<64>; // gas ceiling for the call
|
|
465
|
-
to: Bytes<20>; //
|
|
533
|
+
to: Bytes<20>; // recipient (e.g. the ERC20 contract)
|
|
466
534
|
value: Uint<128>; // ETH sent with the call, in wei
|
|
467
535
|
calldata: Maybe<EvmCalldata<maxCalldataWords>>; // none = plain ETH transfer ("0x" data)
|
|
468
536
|
accessListEntryCount: Uint<8>; // how many leading accessList entries are real
|
package/src/circuits.compact
CHANGED
|
@@ -12,6 +12,8 @@ export {
|
|
|
12
12
|
HashDomain,
|
|
13
13
|
OutputKind,
|
|
14
14
|
calculateRequestIdV1,
|
|
15
|
+
calculateSignetAttestationDigestV1,
|
|
16
|
+
verifyRespondBidirectionalAttestationV1,
|
|
15
17
|
constructSignBidirectionalEventNotificationV1,
|
|
16
18
|
ethereumCaip2Id,
|
|
17
19
|
evmAddressAbiWord,
|
|
@@ -22,56 +24,62 @@ export {
|
|
|
22
24
|
checkedTruncationU128
|
|
23
25
|
};
|
|
24
26
|
|
|
25
|
-
// ---- Fixed-width
|
|
26
|
-
// The size-generic
|
|
27
|
-
// list above. These fixed-width instantiations exist solely to pin
|
|
28
|
-
// twin in ecdsa-attestation.ts against the compiled circuits (widths
|
|
29
|
-
// 32 and 100, where 0 is the empty output of a failed or unviable
|
|
30
|
-
// Client contracts instantiate the generic circuits at their own
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
blockHeight: Uint<64>,
|
|
35
|
-
outputKind: OutputKind,
|
|
27
|
+
// ---- Fixed-width output hash oracles (tests only) --------------------------
|
|
28
|
+
// The size-generic output hash and verify circuits cannot appear in the
|
|
29
|
+
// export list above. These fixed-width instantiations exist solely to pin
|
|
30
|
+
// the TS twin in ecdsa-attestation.ts against the compiled circuits (widths
|
|
31
|
+
// 0, 1, 2, 32 and 100, where 0 is the empty output of a failed or unviable
|
|
32
|
+
// execution). Client contracts instantiate the generic circuits at their own
|
|
33
|
+
// width.
|
|
34
|
+
|
|
35
|
+
export pure circuit calculateAttestedOutputHash0(
|
|
36
36
|
serializedOutput: Bytes<0>
|
|
37
37
|
): Bytes<32> {
|
|
38
|
-
return
|
|
38
|
+
return calculateAttestedOutputHashV1<0>(serializedOutput);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export pure circuit
|
|
42
|
-
requestId: RequestId,
|
|
43
|
-
blockHeight: Uint<64>,
|
|
44
|
-
outputKind: OutputKind,
|
|
41
|
+
export pure circuit calculateAttestedOutputHash1(
|
|
45
42
|
serializedOutput: Bytes<1>
|
|
46
43
|
): Bytes<32> {
|
|
47
|
-
return
|
|
44
|
+
return calculateAttestedOutputHashV1<1>(serializedOutput);
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
export pure circuit
|
|
51
|
-
requestId: RequestId,
|
|
52
|
-
blockHeight: Uint<64>,
|
|
53
|
-
outputKind: OutputKind,
|
|
47
|
+
export pure circuit calculateAttestedOutputHash2(
|
|
54
48
|
serializedOutput: Bytes<2>
|
|
55
49
|
): Bytes<32> {
|
|
56
|
-
return
|
|
50
|
+
return calculateAttestedOutputHashV1<2>(serializedOutput);
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
export pure circuit
|
|
60
|
-
requestId: RequestId,
|
|
61
|
-
blockHeight: Uint<64>,
|
|
62
|
-
outputKind: OutputKind,
|
|
53
|
+
export pure circuit calculateAttestedOutputHash32(
|
|
63
54
|
serializedOutput: Bytes<32>
|
|
64
55
|
): Bytes<32> {
|
|
65
|
-
return
|
|
56
|
+
return calculateAttestedOutputHashV1<32>(serializedOutput);
|
|
66
57
|
}
|
|
67
58
|
|
|
68
|
-
export pure circuit
|
|
69
|
-
requestId: RequestId,
|
|
70
|
-
blockHeight: Uint<64>,
|
|
71
|
-
outputKind: OutputKind,
|
|
59
|
+
export pure circuit calculateAttestedOutputHash100(
|
|
72
60
|
serializedOutput: Bytes<100>
|
|
73
61
|
): Bytes<32> {
|
|
74
|
-
return
|
|
62
|
+
return calculateAttestedOutputHashV1<100>(serializedOutput);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Fixed-width instantiations of verifyAttestedOutputV1, pinning its TS twin
|
|
66
|
+
// verifyAttestedOutput, including the trailing-zero case the length check
|
|
67
|
+
// exists for (a 2-byte output against a 1-byte attestation).
|
|
68
|
+
|
|
69
|
+
export pure circuit verifyAttestedOutput1(
|
|
70
|
+
serializedOutput: Bytes<1>,
|
|
71
|
+
attestedOutputLength: Uint<64>,
|
|
72
|
+
attestedOutputHash: Bytes<32>
|
|
73
|
+
): Boolean {
|
|
74
|
+
return verifyAttestedOutputV1<1>(serializedOutput, attestedOutputLength, attestedOutputHash);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export pure circuit verifyAttestedOutput2(
|
|
78
|
+
serializedOutput: Bytes<2>,
|
|
79
|
+
attestedOutputLength: Uint<64>,
|
|
80
|
+
attestedOutputHash: Bytes<32>
|
|
81
|
+
): Boolean {
|
|
82
|
+
return verifyAttestedOutputV1<2>(serializedOutput, attestedOutputLength, attestedOutputHash);
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
// ---- Fixed-width transaction digest oracles (tests only) --------------------
|