@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.
Files changed (52) hide show
  1. package/README.md +9 -8
  2. package/dist/abi-serde.d.ts +7 -5
  3. package/dist/abi-serde.d.ts.map +1 -1
  4. package/dist/abi-serde.js +9 -6
  5. package/dist/abi-serde.js.map +1 -1
  6. package/dist/compact-descriptors.d.ts +5 -7
  7. package/dist/compact-descriptors.d.ts.map +1 -1
  8. package/dist/compact-descriptors.js +7 -19
  9. package/dist/compact-descriptors.js.map +1 -1
  10. package/dist/constants.d.ts +7 -4
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +7 -4
  13. package/dist/constants.js.map +1 -1
  14. package/dist/ecdsa-attestation.d.ts +61 -12
  15. package/dist/ecdsa-attestation.d.ts.map +1 -1
  16. package/dist/ecdsa-attestation.js +92 -39
  17. package/dist/ecdsa-attestation.js.map +1 -1
  18. package/dist/epsilon-derivation.d.ts +9 -7
  19. package/dist/epsilon-derivation.d.ts.map +1 -1
  20. package/dist/epsilon-derivation.js +6 -5
  21. package/dist/epsilon-derivation.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/managed/compiler/contract-info.json +251 -143
  27. package/dist/managed/compiler/contract-manifest.json +8 -8
  28. package/dist/managed/contract/index.d.ts +75 -46
  29. package/dist/managed/contract/index.js +604 -585
  30. package/dist/managed/contract/index.js.map +1 -1
  31. package/dist/mpc-output-cache.d.ts +7 -5
  32. package/dist/mpc-output-cache.d.ts.map +1 -1
  33. package/dist/mpc-output-cache.js +6 -5
  34. package/dist/mpc-output-cache.js.map +1 -1
  35. package/dist/signet-contract-events.d.ts +20 -11
  36. package/dist/signet-contract-events.d.ts.map +1 -1
  37. package/dist/signet-contract-events.js +9 -6
  38. package/dist/signet-contract-events.js.map +1 -1
  39. package/dist/signet-evtype2tx-record-decoding.js +2 -2
  40. package/dist/signet-evtype2tx-requests.d.ts +3 -5
  41. package/dist/signet-evtype2tx-requests.d.ts.map +1 -1
  42. package/dist/signet-evtype2tx-requests.js +2 -4
  43. package/dist/signet-evtype2tx-requests.js.map +1 -1
  44. package/dist/signet-requests.d.ts +7 -6
  45. package/dist/signet-requests.d.ts.map +1 -1
  46. package/dist/signet-requests.js +2 -2
  47. package/dist/signet-requests.js.map +1 -1
  48. package/dist/testing.js +1 -1
  49. package/dist/testing.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/Signet.compact +138 -70
  52. package/src/circuits.compact +40 -32
@@ -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 that the foreign chain executed the
30
- // signed transaction.
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 verify them). Vocabulary
34
- // shared across versions (RequestId, OutputKind, Signature, the enums, the transaction parameter
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 destination chain.
49
- // 4. MPC observes txn execution on destination chain and posts a RespondBidirectionalEvent attestation
50
- // through the Signet singleton, which emits it as a contract event beside the request id.
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, or the exact attested bytes from the
54
- // MPC's output cache) and hands output plus attestation to its verify circuit. See
55
- // "Output Recovery" in the repository README.
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: this package's README
59
- // ("Sign bidirectional flow", "Derived keys").
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
- // Specific destination chain Transaction parameters.
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<32>; // The MPC's routing key for the target chain, in CAIP-2 form
111
- // (https://chainagnostic.org/CAIPs/caip-2). An Ethereum target
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 destination chain's
123
- // execution output (destination chain -> MPC).
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<32>,
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<32>;
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
- // attestationDigest = calculateSignetAttestationDigestV1(requestId, blockHeight, outputKind, serializedOutput)
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 and the digest is recomputed at verification
341
- // time (verifyRespondBidirectionalEventV1). The signature is the ONLY thing that
342
- // distinguishes a genuine post from garbage: the singleton emits every post
343
- // unverified.
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 destination block holding the transaction the
350
- // attestation describes, in the destination chain's own numbering (a slot
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 the digest commits to (0 for a failed
356
- // or unviable execution), so a client holding no output yet knows which
357
- // width to settle at.
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
- // so a reader holding no output can check the signature. The verifying
361
- // circuit recomputes it from the output and never reads this copy.
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 destination block that settled the verdict.
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 carrying other bytes took the nonce: the attested output is empty (Bytes<0>)
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 attestation digest of a remote execution output:
377
- // attestationDigest = upgradeFromTransient(transientHash([HashDomain.attestationDigest, requestId, blockHeight, outputKind, serializedOutputLength, serializedOutput]))
378
- // blockHeight is the height of the finalised destination block holding the
379
- // transaction the attestation describes, in the destination chain's own
380
- // numbering (a slot on Solana).
381
- // Off-chain code uses the TypeScript twin:
382
- // import { calculateSignetAttestationDigest } from "@sig-net/midnight/testing";
383
- export pure circuit calculateSignetAttestationDigestV1<#serializedOutputLength>(
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
- serializedOutput: Bytes<serializedOutputLength>,
413
+ serializedOutputLength: Uint<64>,
414
+ outputHash: Bytes<32>,
388
415
  ): Bytes<32> {
389
- return upgradeFromTransient(transientHash<[HashDomain, RequestId, Uint<64>, OutputKind, Uint<64>, Bytes<serializedOutputLength>]>([HashDomain.attestationDigest, requestId, blockHeight, outputKind, serializedOutputLength, serializedOutput]));
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 its execution output and MPC
393
- // response key: recomputes the digest over the request id, block height,
394
- // output kind, output length and caller's output, then verifies its signature. Client
395
- // contracts run this before consuming outputs, as the singleton emits
396
- // responses unverified. The caller supplies
397
- // serializedOutput at its exact unpadded width, and the event record with
398
- // signature.bigR.x and signature.s byte-reversed into LITTLE-endian: the
399
- // scalar casts below read little-endian bytes, and the wire/ledger records
400
- // are big-endian, so the reversal happens off-chain where it costs nothing
401
- // (the TS SDK's respondBidirectionalEventToCircuitInput does it). A wrong
402
- // byte order fails verification, never a false accept. Of the event, requestId,
403
- // blockHeight, outputKind, signature.bigR.x and signature.s enter verification:
404
- // serializedOutputLength and digest serve off-chain readers. The digest binds
405
- // the event's requestId, so a client MUST consume that request and no other. An s
406
- // that reduces to 0 mod the curve order aborts the
407
- // circuit rather than returning false, so sift candidate posts off chain
408
- // first (verifyRespondBidirectionalSignature).
409
- export pure circuit verifyRespondBidirectionalEventV1<#serializedOutputLength>(
410
- serializedOutput: Bytes<serializedOutputLength>,
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<serializedOutputLength>(
441
+ const digest = calculateSignetAttestationDigestV1(
415
442
  respondBidirectionalEvent.requestId,
416
443
  respondBidirectionalEvent.blockHeight,
417
444
  respondBidirectionalEvent.outputKind,
418
- serializedOutput,
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 node watches (mainnet, Sepolia or a local anvil: node configuration picks it).
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<32> {
441
- return pad(32, "eip155:1");
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>; // call target (e.g. the ERC20 contract)
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
@@ -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 attestation oracles (tests only) --------------------------
26
- // The size-generic digest and verify circuits cannot appear in the export
27
- // list above. These fixed-width instantiations exist solely to pin the TS
28
- // twin in ecdsa-attestation.ts against the compiled circuits (widths 0, 1, 2,
29
- // 32 and 100, where 0 is the empty output of a failed or unviable execution).
30
- // Client contracts instantiate the generic circuits at their own width.
31
-
32
- export pure circuit calculateSignetAttestationDigest0(
33
- requestId: RequestId,
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 calculateSignetAttestationDigestV1<0>(requestId, blockHeight, outputKind, serializedOutput);
38
+ return calculateAttestedOutputHashV1<0>(serializedOutput);
39
39
  }
40
40
 
41
- export pure circuit calculateSignetAttestationDigest1(
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 calculateSignetAttestationDigestV1<1>(requestId, blockHeight, outputKind, serializedOutput);
44
+ return calculateAttestedOutputHashV1<1>(serializedOutput);
48
45
  }
49
46
 
50
- export pure circuit calculateSignetAttestationDigest2(
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 calculateSignetAttestationDigestV1<2>(requestId, blockHeight, outputKind, serializedOutput);
50
+ return calculateAttestedOutputHashV1<2>(serializedOutput);
57
51
  }
58
52
 
59
- export pure circuit calculateSignetAttestationDigest32(
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 calculateSignetAttestationDigestV1<32>(requestId, blockHeight, outputKind, serializedOutput);
56
+ return calculateAttestedOutputHashV1<32>(serializedOutput);
66
57
  }
67
58
 
68
- export pure circuit calculateSignetAttestationDigest100(
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 calculateSignetAttestationDigestV1<100>(requestId, blockHeight, outputKind, serializedOutput);
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) --------------------