@sig-net/midnight 0.0.4 → 0.0.6
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 -15
- package/dist/ecdsa.d.ts +114 -0
- package/dist/ecdsa.d.ts.map +1 -0
- package/dist/ecdsa.js +145 -0
- package/dist/ecdsa.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/managed/compiler/contract-info.json +2 -49
- package/dist/managed/compiler/contract-manifest.json +8 -8
- package/dist/managed/contract/index.d.ts +2 -13
- package/dist/managed/contract/index.js +58 -161
- package/dist/managed/contract/index.js.map +2 -2
- package/dist/signet-contract-state-reader.d.ts +18 -14
- package/dist/signet-contract-state-reader.d.ts.map +1 -1
- package/dist/signet-contract-state-reader.js +10 -12
- package/dist/signet-contract-state-reader.js.map +1 -1
- package/dist/signet-request-response-reader.d.ts +4 -4
- package/dist/signet-request-response-reader.js +4 -4
- package/dist/signet-requests.js +1 -1
- package/dist/signet-requests.js.map +1 -1
- package/package.json +1 -1
- package/src/Signet.compact +47 -37
- package/src/circuits.compact +6 -8
- package/dist/schnorr.d.ts +0 -100
- package/dist/schnorr.d.ts.map +0 -1
- package/dist/schnorr.js +0 -144
- package/dist/schnorr.js.map +0 -1
- package/src/Schnorr.compact +0 -63
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ The client-agnostic [Sig Network](https://sig.network) protocol library for the
|
|
|
8
8
|
```compact
|
|
9
9
|
import "@sig-net/midnight/src/Signet";
|
|
10
10
|
```
|
|
11
|
-
- **Compiled pure circuits** (`pureCircuits`): the executable reference implementation of the client-agnostic circuits (path/identity checks, the attestation
|
|
11
|
+
- **Compiled pure circuits** (`pureCircuits`): the executable reference implementation of the client-agnostic circuits (path/identity checks, the attestation-message digest, the sign-bidirectional notification packer). Off-chain code calls these compiled artefacts instead of re-porting the algorithms, so it always agrees with what the contracts prove.
|
|
12
12
|
- **TypeScript twins of the wire structs** and signet request-id computation.
|
|
13
13
|
- **State readers, request feed and resolver**: poll the signet contract for pending requests and their signature / remote-execution responses.
|
|
14
|
-
- **Crypto helpers**: epsilon derivation and
|
|
14
|
+
- **Crypto helpers**: epsilon derivation and secp256k1 ECDSA attestation signing/verification.
|
|
15
15
|
|
|
16
16
|
Where signet.js already covers something (for example EVM transaction preparation or address derivation), import it from there; only what is Midnight-specific lives here.
|
|
17
17
|
|
|
@@ -28,7 +28,7 @@ A signet-compliant client contract does four things:
|
|
|
28
28
|
1. **Stores requests in a public index**: a `SignBidirectionalRequestIndex` map in its ledger. The index can sit at ANY ledger field: each notification the contract registers names the field position holding it, and the MPC reads the authenticated request from there. A contract-local `SignetNonce` counter is a convenient source of request nonces (identical requests must hash to distinct ids); nothing off-chain reads it.
|
|
29
29
|
2. **Pins its counterparties at deploy time**: the central signet contract it notifies, and the MPC attestation key its verify circuit accepts.
|
|
30
30
|
3. **Submits signature requests**: builds the transaction decomposition in-circuit, constructs the canonical request record, stores it in its own index under the request id, and registers a notification in the central registry (which the MPC polls; the MPC then reads the authenticated request back from the ledger field the notification names).
|
|
31
|
-
4. **Verifies the execution response**: checks the attestation key, verifies the MPC's
|
|
31
|
+
4. **Verifies the execution response**: checks the attestation key, verifies the MPC's secp256k1 ECDSA attestation in-circuit over the digest of (request id, output), and consumes the request.
|
|
32
32
|
|
|
33
33
|
```compact
|
|
34
34
|
pragma language_version >= 0.25;
|
|
@@ -49,8 +49,8 @@ export ledger signetNonce: SignetNonce;
|
|
|
49
49
|
export sealed ledger mpcPubKeyHash: Bytes<32>;
|
|
50
50
|
sealed ledger signetNotifier: SignetNotifier;
|
|
51
51
|
|
|
52
|
-
constructor(mpcPk:
|
|
53
|
-
mpcPubKeyHash = disclose(persistentHash<
|
|
52
|
+
constructor(mpcPk: Secp256k1Point, signetContract: SignetNotifier) {
|
|
53
|
+
mpcPubKeyHash = disclose(persistentHash<Secp256k1Point>(mpcPk));
|
|
54
54
|
signetNotifier = disclose(signetContract);
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -103,22 +103,27 @@ export circuit submitSignatureRequest(evmNonce: Uint<64>, keyVersion: Uint<32>):
|
|
|
103
103
|
constructSignBidirectionalNotificationV1(kernel.self(), requestId as Bytes<32>, 0 as Uint<8>));
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// (4) Verify the MPC's
|
|
107
|
-
// and consume the request (double-verify protection).
|
|
108
|
-
|
|
106
|
+
// (4) Verify the MPC's secp256k1 ECDSA-signed attestation of the remote
|
|
107
|
+
// execution and consume the request (double-verify protection). The signing
|
|
108
|
+
// public key is passed alongside the record and pinned by hash.
|
|
109
|
+
export circuit verifyResponse(
|
|
110
|
+
requestId: RequestId,
|
|
111
|
+
respondBidirectional: RespondBidirectional,
|
|
112
|
+
pk: Secp256k1Point
|
|
113
|
+
): [] {
|
|
109
114
|
const rid = disclose(requestId);
|
|
110
115
|
assert(
|
|
111
|
-
persistentHash<
|
|
116
|
+
persistentHash<Secp256k1Point>(pk) == mpcPubKeyHash,
|
|
112
117
|
"Unauthorized: attestation pk is not the MPC key"
|
|
113
118
|
);
|
|
114
119
|
assert(
|
|
115
|
-
|
|
120
|
+
secp256k1EcdsaVerify(
|
|
116
121
|
signetAttestationMessage(rid, respondBidirectional.serializedOutput, respondBidirectional.outputLen),
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
Secp256k1EcdsaSignature {
|
|
123
|
+
r: respondBidirectional.sigR as Secp256k1Scalar,
|
|
124
|
+
s: respondBidirectional.sigS as Secp256k1Scalar,
|
|
120
125
|
},
|
|
121
|
-
|
|
126
|
+
pk
|
|
122
127
|
),
|
|
123
128
|
"Invalid attestation signature"
|
|
124
129
|
);
|
|
@@ -127,7 +132,7 @@ export circuit verifyResponse(requestId: RequestId, respondBidirectional: Respon
|
|
|
127
132
|
}
|
|
128
133
|
```
|
|
129
134
|
|
|
130
|
-
Between the two circuits sit the off-chain steps, which this package also covers: poll the central signet contract with `SignetRequestResponseReader` (configured with both contract addresses and the ledger field position of your request index) to collect and verify the MPC's secp256k1 signature (then broadcast the signed transaction to the destination chain), and later the
|
|
135
|
+
Between the two circuits sit the off-chain steps, which this package also covers: poll the central signet contract with `SignetRequestResponseReader` (configured with both contract addresses and the ledger field position of your request index) to collect and verify the MPC's secp256k1 signature (then broadcast the signed transaction to the destination chain), and later the ECDSA-attested execution output to feed back into `verifyResponse`.
|
|
131
136
|
|
|
132
137
|
The [signet-caller contract](https://github.com/sig-net/midnight-integration/blob/main/packages/caller-contract/src/signet-caller.compact) is the complete, runnable version of this skeleton, exercised end to end by the repository's integration suite; a fuller application (an ERC20 cross-chain vault) lives in [sig-net/midnight-examples](https://github.com/sig-net/midnight-examples).
|
|
133
138
|
|
package/dist/ecdsa.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type Secp256k1Point } from "@midnight-ntwrk/compact-runtime";
|
|
2
|
+
export type { Secp256k1Point } from "@midnight-ntwrk/compact-runtime";
|
|
3
|
+
/** secp256k1 curve (group) order n — the scalar field the signature r, s live in. */
|
|
4
|
+
export declare const SECP256K1_ORDER: bigint;
|
|
5
|
+
/**
|
|
6
|
+
* BLS12-381 scalar field order (the Compact `Field` type modulus). Retained
|
|
7
|
+
* because {@link bigintToBytes32} interprets negative `Field` values in it and
|
|
8
|
+
* signet-requests.ts imports the byte helpers below.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BLS_ORDER = 52435875175126190479447740508185965837690552500527637822603658699938581184513n;
|
|
11
|
+
/**
|
|
12
|
+
* Convert little-endian bytes to a bigint. Matches Compact's
|
|
13
|
+
* `Bytes<32> as Field` / `Bytes<32> as Secp256k1Scalar` interpretation (and
|
|
14
|
+
* the MPC monitor's ABI-word decoding convention).
|
|
15
|
+
*
|
|
16
|
+
* @param bytes - Little-endian byte array.
|
|
17
|
+
* @returns The decoded non-negative integer.
|
|
18
|
+
*/
|
|
19
|
+
export declare function bytesToBigint(bytes: Uint8Array): bigint;
|
|
20
|
+
/**
|
|
21
|
+
* Convert a bigint to exactly 32 little-endian bytes. Matches Compact's
|
|
22
|
+
* `Field as Bytes<32>` / `Secp256k1Scalar as Bytes<32>` encoding (the inverse
|
|
23
|
+
* of {@link bytesToBigint}); negative inputs are interpreted in the BLS scalar
|
|
24
|
+
* field.
|
|
25
|
+
*
|
|
26
|
+
* @param n - The integer to encode.
|
|
27
|
+
* @returns The 32-byte little-endian encoding.
|
|
28
|
+
*/
|
|
29
|
+
export declare function bigintToBytes32(n: bigint): Uint8Array;
|
|
30
|
+
/**
|
|
31
|
+
* An ECDSA signature over the attestation digest (TS twin of
|
|
32
|
+
* CompactStandardLibrary's `Secp256k1EcdsaSignature`). Both scalars are plain
|
|
33
|
+
* bigints mod {@link SECP256K1_ORDER}; convert to the ledger form with
|
|
34
|
+
* {@link ecdsaSignatureToLeBytes}.
|
|
35
|
+
*/
|
|
36
|
+
export interface EcdsaSignature {
|
|
37
|
+
/** Signature scalar r. */
|
|
38
|
+
r: bigint;
|
|
39
|
+
/** Signature scalar s (low-s normalized by {@link signAttestation}). */
|
|
40
|
+
s: bigint;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The little-endian 32-byte scalar encoding of an {@link EcdsaSignature} — the
|
|
44
|
+
* exact `sigR`/`sigS` bytes the Compact `RespondBidirectional` struct stores
|
|
45
|
+
* (the byte order the `Secp256k1Scalar as Bytes<32>` cast produces).
|
|
46
|
+
*/
|
|
47
|
+
export interface EcdsaSignatureBytes {
|
|
48
|
+
/** Signature scalar r as 32 little-endian bytes. */
|
|
49
|
+
sigR: Uint8Array;
|
|
50
|
+
/** Signature scalar s as 32 little-endian bytes. */
|
|
51
|
+
sigS: Uint8Array;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sign a 32-byte attestation digest with secp256k1 ECDSA, matching
|
|
55
|
+
* CompactStandardLibrary's `secp256k1EcdsaVerify`: the digest IS the message
|
|
56
|
+
* hash (interpreted big-endian, RFC 6979), so signing is `prehash: false` —
|
|
57
|
+
* noble must not re-hash it. The digest is the compiled
|
|
58
|
+
* `pureCircuits.signetAttestationMessage(requestId, serializedOutput,
|
|
59
|
+
* outputLen)`. noble normalizes to low-s by default; the verifier accepts
|
|
60
|
+
* either s, so this is a convention, not a requirement.
|
|
61
|
+
*
|
|
62
|
+
* @param digest - The 32-byte attestation digest to sign.
|
|
63
|
+
* @param secretKey - The 32-byte secp256k1 private key (the MPC root key).
|
|
64
|
+
* @returns The signature `{ r, s }`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function signAttestation(digest: Uint8Array, secretKey: Uint8Array): EcdsaSignature;
|
|
67
|
+
/**
|
|
68
|
+
* Encode an {@link EcdsaSignature}'s scalars as the little-endian 32-byte
|
|
69
|
+
* `sigR`/`sigS` the Compact `RespondBidirectional` struct stores — the form
|
|
70
|
+
* the verifying circuits cast back with `as Secp256k1Scalar`.
|
|
71
|
+
*
|
|
72
|
+
* @param signature - The signature to encode.
|
|
73
|
+
* @returns The `{ sigR, sigS }` little-endian scalar bytes.
|
|
74
|
+
*/
|
|
75
|
+
export declare function ecdsaSignatureToLeBytes(signature: EcdsaSignature): EcdsaSignatureBytes;
|
|
76
|
+
/**
|
|
77
|
+
* Derive the secp256k1 public key point from a private key — the MPC
|
|
78
|
+
* attestation key, which is the MPC root key used directly as the secp256k1
|
|
79
|
+
* private key (the same key the EVM signing accounts epsilon-derive from).
|
|
80
|
+
*
|
|
81
|
+
* @param secretKey - The 32-byte secp256k1 private key (the MPC root key).
|
|
82
|
+
* @returns The public key as a {@link Secp256k1Point}.
|
|
83
|
+
*/
|
|
84
|
+
export declare function secp256k1PublicKeyFromSecretKey(secretKey: Uint8Array): Secp256k1Point;
|
|
85
|
+
/**
|
|
86
|
+
* Parse a secp256k1 public key from its 0x-hex config/env form (compressed
|
|
87
|
+
* 33-byte or uncompressed 65-byte) into the runtime's point shape — how
|
|
88
|
+
* deploys receive `MPC_SECP256K1_PUBKEY`.
|
|
89
|
+
*
|
|
90
|
+
* @param value - The 0x-hex public key (0x prefix optional).
|
|
91
|
+
* @returns The parsed point.
|
|
92
|
+
* @throws Error if the value is not a valid secp256k1 point encoding.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseSecp256k1PublicKey(value: string): Secp256k1Point;
|
|
95
|
+
/**
|
|
96
|
+
* Format a secp256k1 public key as the compressed 0x-hex config/env form that
|
|
97
|
+
* {@link parseSecp256k1PublicKey} accepts — the round-trip inverse, for
|
|
98
|
+
* handing a derived key to deploys as `MPC_SECP256K1_PUBKEY`.
|
|
99
|
+
*
|
|
100
|
+
* @param point - The point to format.
|
|
101
|
+
* @returns The compressed public key as 0x-prefixed hex.
|
|
102
|
+
* @throws Error if the point is the identity (has no compressed encoding).
|
|
103
|
+
*/
|
|
104
|
+
export declare function formatSecp256k1PublicKey(point: Secp256k1Point): string;
|
|
105
|
+
/**
|
|
106
|
+
* Hash a secp256k1 point exactly as the circuits do
|
|
107
|
+
* (`persistentHash<Secp256k1Point>`) — the form the signet contract and caller
|
|
108
|
+
* seal as `mpcPubKeyHash`.
|
|
109
|
+
*
|
|
110
|
+
* @param point - The point to hash.
|
|
111
|
+
* @returns The 32-byte hash.
|
|
112
|
+
*/
|
|
113
|
+
export declare function hashSecp256k1Point(point: Secp256k1Point): Uint8Array;
|
|
114
|
+
//# sourceMappingURL=ecdsa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../src/ecdsa.ts"],"names":[],"mappings":"AAgBA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,iCAAiC,CAAC;AAKzC,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,qFAAqF;AACrF,eAAO,MAAM,eAAe,QAA2B,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,SAAS,iFAAiF,CAAC;AAExG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAQrD;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,wEAAwE;IACxE,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,IAAI,EAAE,UAAU,CAAC;IACjB,oDAAoD;IACpD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,UAAU,GACpB,cAAc,CAMhB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,cAAc,GACxB,mBAAmB,CAKrB;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,UAAU,GACpB,cAAc,CAGhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAUrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAKtE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAEpE"}
|
package/dist/ecdsa.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// secp256k1 ECDSA helpers — the TS side of the shared attestation flow:
|
|
2
|
+
// SIGNING (which needs the secret scalar, so it cannot be a circuit), key
|
|
3
|
+
// parsing/formatting/hashing, and the little-endian scalar-byte plumbing the
|
|
4
|
+
// ledger struct stores. Everything provable stays in Compact: the attestation
|
|
5
|
+
// message is the COMPILED `pureCircuits.signetAttestationMessage` (this file
|
|
6
|
+
// never re-implements it) and verification is CompactStandardLibrary's
|
|
7
|
+
// `secp256k1EcdsaVerify`, run by the signet contract at post time and by the
|
|
8
|
+
// caller at settle time.
|
|
9
|
+
//
|
|
10
|
+
// This belongs in github.com/sig-net/signet.js as its Midnight adapter —
|
|
11
|
+
// kept here until upstreamed. It is Midnight-specific only in the point-hash
|
|
12
|
+
// form (`persistentHash<Secp256k1Point>` via @midnight-ntwrk/compact-runtime),
|
|
13
|
+
// which is exactly the deploy-time key pin the contracts seal.
|
|
14
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
15
|
+
import { CompactTypeSecp256k1Point, persistentHash, } from "@midnight-ntwrk/compact-runtime";
|
|
16
|
+
/** secp256k1 curve (group) order n — the scalar field the signature r, s live in. */
|
|
17
|
+
export const SECP256K1_ORDER = secp256k1.Point.Fn.ORDER;
|
|
18
|
+
/**
|
|
19
|
+
* BLS12-381 scalar field order (the Compact `Field` type modulus). Retained
|
|
20
|
+
* because {@link bigintToBytes32} interprets negative `Field` values in it and
|
|
21
|
+
* signet-requests.ts imports the byte helpers below.
|
|
22
|
+
*/
|
|
23
|
+
export const BLS_ORDER = 52435875175126190479447740508185965837690552500527637822603658699938581184513n;
|
|
24
|
+
/**
|
|
25
|
+
* Convert little-endian bytes to a bigint. Matches Compact's
|
|
26
|
+
* `Bytes<32> as Field` / `Bytes<32> as Secp256k1Scalar` interpretation (and
|
|
27
|
+
* the MPC monitor's ABI-word decoding convention).
|
|
28
|
+
*
|
|
29
|
+
* @param bytes - Little-endian byte array.
|
|
30
|
+
* @returns The decoded non-negative integer.
|
|
31
|
+
*/
|
|
32
|
+
export function bytesToBigint(bytes) {
|
|
33
|
+
let result = 0n;
|
|
34
|
+
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
35
|
+
result = (result << 8n) | BigInt(bytes[i]);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Convert a bigint to exactly 32 little-endian bytes. Matches Compact's
|
|
41
|
+
* `Field as Bytes<32>` / `Secp256k1Scalar as Bytes<32>` encoding (the inverse
|
|
42
|
+
* of {@link bytesToBigint}); negative inputs are interpreted in the BLS scalar
|
|
43
|
+
* field.
|
|
44
|
+
*
|
|
45
|
+
* @param n - The integer to encode.
|
|
46
|
+
* @returns The 32-byte little-endian encoding.
|
|
47
|
+
*/
|
|
48
|
+
export function bigintToBytes32(n) {
|
|
49
|
+
const buf = new Uint8Array(32);
|
|
50
|
+
let v = n < 0n ? n + BLS_ORDER : n;
|
|
51
|
+
for (let i = 0; i < 32; i++) {
|
|
52
|
+
buf[i] = Number(v & 0xffn);
|
|
53
|
+
v >>= 8n;
|
|
54
|
+
}
|
|
55
|
+
return buf;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sign a 32-byte attestation digest with secp256k1 ECDSA, matching
|
|
59
|
+
* CompactStandardLibrary's `secp256k1EcdsaVerify`: the digest IS the message
|
|
60
|
+
* hash (interpreted big-endian, RFC 6979), so signing is `prehash: false` —
|
|
61
|
+
* noble must not re-hash it. The digest is the compiled
|
|
62
|
+
* `pureCircuits.signetAttestationMessage(requestId, serializedOutput,
|
|
63
|
+
* outputLen)`. noble normalizes to low-s by default; the verifier accepts
|
|
64
|
+
* either s, so this is a convention, not a requirement.
|
|
65
|
+
*
|
|
66
|
+
* @param digest - The 32-byte attestation digest to sign.
|
|
67
|
+
* @param secretKey - The 32-byte secp256k1 private key (the MPC root key).
|
|
68
|
+
* @returns The signature `{ r, s }`.
|
|
69
|
+
*/
|
|
70
|
+
export function signAttestation(digest, secretKey) {
|
|
71
|
+
const signature = secp256k1.Signature.fromBytes(secp256k1.sign(digest, secretKey, { prehash: false }), "compact");
|
|
72
|
+
return { r: signature.r, s: signature.s };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Encode an {@link EcdsaSignature}'s scalars as the little-endian 32-byte
|
|
76
|
+
* `sigR`/`sigS` the Compact `RespondBidirectional` struct stores — the form
|
|
77
|
+
* the verifying circuits cast back with `as Secp256k1Scalar`.
|
|
78
|
+
*
|
|
79
|
+
* @param signature - The signature to encode.
|
|
80
|
+
* @returns The `{ sigR, sigS }` little-endian scalar bytes.
|
|
81
|
+
*/
|
|
82
|
+
export function ecdsaSignatureToLeBytes(signature) {
|
|
83
|
+
return {
|
|
84
|
+
sigR: bigintToBytes32(signature.r),
|
|
85
|
+
sigS: bigintToBytes32(signature.s),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Derive the secp256k1 public key point from a private key — the MPC
|
|
90
|
+
* attestation key, which is the MPC root key used directly as the secp256k1
|
|
91
|
+
* private key (the same key the EVM signing accounts epsilon-derive from).
|
|
92
|
+
*
|
|
93
|
+
* @param secretKey - The 32-byte secp256k1 private key (the MPC root key).
|
|
94
|
+
* @returns The public key as a {@link Secp256k1Point}.
|
|
95
|
+
*/
|
|
96
|
+
export function secp256k1PublicKeyFromSecretKey(secretKey) {
|
|
97
|
+
const point = secp256k1.Point.fromBytes(secp256k1.getPublicKey(secretKey, false));
|
|
98
|
+
return { x: point.x, y: point.y, identity: false };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parse a secp256k1 public key from its 0x-hex config/env form (compressed
|
|
102
|
+
* 33-byte or uncompressed 65-byte) into the runtime's point shape — how
|
|
103
|
+
* deploys receive `MPC_SECP256K1_PUBKEY`.
|
|
104
|
+
*
|
|
105
|
+
* @param value - The 0x-hex public key (0x prefix optional).
|
|
106
|
+
* @returns The parsed point.
|
|
107
|
+
* @throws Error if the value is not a valid secp256k1 point encoding.
|
|
108
|
+
*/
|
|
109
|
+
export function parseSecp256k1PublicKey(value) {
|
|
110
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
111
|
+
try {
|
|
112
|
+
const point = secp256k1.Point.fromHex(hex);
|
|
113
|
+
return { x: point.x, y: point.y, identity: false };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
throw new Error(`expected a secp256k1 public key as compressed/uncompressed 0x-hex; got "${value}"`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Format a secp256k1 public key as the compressed 0x-hex config/env form that
|
|
121
|
+
* {@link parseSecp256k1PublicKey} accepts — the round-trip inverse, for
|
|
122
|
+
* handing a derived key to deploys as `MPC_SECP256K1_PUBKEY`.
|
|
123
|
+
*
|
|
124
|
+
* @param point - The point to format.
|
|
125
|
+
* @returns The compressed public key as 0x-prefixed hex.
|
|
126
|
+
* @throws Error if the point is the identity (has no compressed encoding).
|
|
127
|
+
*/
|
|
128
|
+
export function formatSecp256k1PublicKey(point) {
|
|
129
|
+
if (point.identity) {
|
|
130
|
+
throw new Error("cannot format the identity point as a public key");
|
|
131
|
+
}
|
|
132
|
+
return `0x${secp256k1.Point.fromAffine({ x: point.x, y: point.y }).toHex(true)}`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Hash a secp256k1 point exactly as the circuits do
|
|
136
|
+
* (`persistentHash<Secp256k1Point>`) — the form the signet contract and caller
|
|
137
|
+
* seal as `mpcPubKeyHash`.
|
|
138
|
+
*
|
|
139
|
+
* @param point - The point to hash.
|
|
140
|
+
* @returns The 32-byte hash.
|
|
141
|
+
*/
|
|
142
|
+
export function hashSecp256k1Point(point) {
|
|
143
|
+
return persistentHash(CompactTypeSecp256k1Point, point);
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=ecdsa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecdsa.js","sourceRoot":"","sources":["../src/ecdsa.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,12 +8,12 @@ export * from "./signet-request-resolver.ts";
|
|
|
8
8
|
export * from "./signet-request-feed.ts";
|
|
9
9
|
export * from "./constants.ts";
|
|
10
10
|
export * from "./epsilon-derivation.ts";
|
|
11
|
-
export * from "./
|
|
11
|
+
export * from "./ecdsa.ts";
|
|
12
12
|
/**
|
|
13
13
|
* Compiled pure circuits of Signet.compact (run `yarn compile` first): the
|
|
14
14
|
* executable reference implementation of the client-agnostic circuits —
|
|
15
|
-
* path<->identity checks, the attestation message, the
|
|
16
|
-
* (`constructSignBidirectionalNotificationV1`)
|
|
15
|
+
* path<->identity checks, the attestation message digest, and the
|
|
16
|
+
* notification packer (`constructSignBidirectionalNotificationV1`).
|
|
17
17
|
* Off-chain code MUST use these instead of re-porting the algorithms — they
|
|
18
18
|
* are the same compiled logic the contracts prove. The generic request
|
|
19
19
|
* circuits cannot be compiled here (type-parameterized): request construction
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,12 +11,12 @@ export * from "./signet-request-resolver.js";
|
|
|
11
11
|
export * from "./signet-request-feed.js";
|
|
12
12
|
export * from "./constants.js";
|
|
13
13
|
export * from "./epsilon-derivation.js";
|
|
14
|
-
export * from "./
|
|
14
|
+
export * from "./ecdsa.js";
|
|
15
15
|
/**
|
|
16
16
|
* Compiled pure circuits of Signet.compact (run `yarn compile` first): the
|
|
17
17
|
* executable reference implementation of the client-agnostic circuits —
|
|
18
|
-
* path<->identity checks, the attestation message, the
|
|
19
|
-
* (`constructSignBidirectionalNotificationV1`)
|
|
18
|
+
* path<->identity checks, the attestation message digest, and the
|
|
19
|
+
* notification packer (`constructSignBidirectionalNotificationV1`).
|
|
20
20
|
* Off-chain code MUST use these instead of re-porting the algorithms — they
|
|
21
21
|
* are the same compiled logic the contracts prove. The generic request
|
|
22
22
|
* circuits cannot be compiled here (type-parameterized): request construction
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,2DAA2D;AAE3D,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,2DAA2D;AAE3D,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC"}
|
|
@@ -109,11 +109,8 @@
|
|
|
109
109
|
}
|
|
110
110
|
],
|
|
111
111
|
"result-type": {
|
|
112
|
-
"type-name": "
|
|
113
|
-
"length":
|
|
114
|
-
"type": {
|
|
115
|
-
"type-name": "Field"
|
|
116
|
-
}
|
|
112
|
+
"type-name": "Bytes",
|
|
113
|
+
"length": 32
|
|
117
114
|
}
|
|
118
115
|
},
|
|
119
116
|
{
|
|
@@ -167,50 +164,6 @@
|
|
|
167
164
|
"types": [
|
|
168
165
|
]
|
|
169
166
|
}
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"name": "schnorrChallenge",
|
|
173
|
-
"pure": true,
|
|
174
|
-
"proof": false,
|
|
175
|
-
"arguments": [
|
|
176
|
-
{
|
|
177
|
-
"name": "ann_x",
|
|
178
|
-
"type": {
|
|
179
|
-
"type-name": "Field"
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
"name": "ann_y",
|
|
184
|
-
"type": {
|
|
185
|
-
"type-name": "Field"
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"name": "pk_x",
|
|
190
|
-
"type": {
|
|
191
|
-
"type-name": "Field"
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
"name": "pk_y",
|
|
196
|
-
"type": {
|
|
197
|
-
"type-name": "Field"
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"name": "msg",
|
|
202
|
-
"type": {
|
|
203
|
-
"type-name": "Vector",
|
|
204
|
-
"length": 4,
|
|
205
|
-
"type": {
|
|
206
|
-
"type-name": "Field"
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
],
|
|
211
|
-
"result-type": {
|
|
212
|
-
"type-name": "Field"
|
|
213
|
-
}
|
|
214
167
|
}
|
|
215
168
|
],
|
|
216
169
|
"witnesses": [
|
|
@@ -7,26 +7,26 @@
|
|
|
7
7
|
"type": "directory",
|
|
8
8
|
"contract-info.json": {
|
|
9
9
|
"type": "file",
|
|
10
|
-
"size":
|
|
11
|
-
"hash": "
|
|
10
|
+
"size": 3509,
|
|
11
|
+
"hash": "1f0bcfc80cd800e4cbbe6cc61d59c4355978b67f75303486c10bfb98f77254a4"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"contract": {
|
|
15
15
|
"type": "directory",
|
|
16
16
|
"index.d.ts": {
|
|
17
17
|
"type": "file",
|
|
18
|
-
"size":
|
|
19
|
-
"hash": "
|
|
18
|
+
"size": 3361,
|
|
19
|
+
"hash": "5537a3d8d3d415797bb278f1a0c579026bb24a22c4ad8183ad9d58575e567c17"
|
|
20
20
|
},
|
|
21
21
|
"index.js": {
|
|
22
22
|
"type": "file",
|
|
23
|
-
"size":
|
|
24
|
-
"hash": "
|
|
23
|
+
"size": 37016,
|
|
24
|
+
"hash": "6bbd1abf0a9071b2dbf0b739e2fcb9db361477036cc3b605791c81e44a4450c7"
|
|
25
25
|
},
|
|
26
26
|
"index.js.map": {
|
|
27
27
|
"type": "file",
|
|
28
|
-
"size":
|
|
29
|
-
"hash": "
|
|
28
|
+
"size": 2658,
|
|
29
|
+
"hash": "516e4a7123f87bd04a313a069d5077b43acf5be0c8440cfb89685a8f07d70ed4"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -19,14 +19,9 @@ export type PureCircuits = {
|
|
|
19
19
|
evmAddressAbiValue(addr_0: Uint8Array): bigint;
|
|
20
20
|
signetAttestationMessage(requestId_0: Uint8Array,
|
|
21
21
|
serializedOutput_0: Uint8Array,
|
|
22
|
-
outputLen_0: bigint):
|
|
22
|
+
outputLen_0: bigint): Uint8Array;
|
|
23
23
|
assertHexOf(commitment_0: Uint8Array, hexStr_0: Uint8Array): [];
|
|
24
24
|
assertPathCommitment(commitment_0: Uint8Array, path_0: Uint8Array): [];
|
|
25
|
-
schnorrChallenge(ann_x_0: bigint,
|
|
26
|
-
ann_y_0: bigint,
|
|
27
|
-
pk_x_0: bigint,
|
|
28
|
-
pk_y_0: bigint,
|
|
29
|
-
msg_0: bigint[]): bigint;
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
export type Circuits<PS> = {
|
|
@@ -42,19 +37,13 @@ export type Circuits<PS> = {
|
|
|
42
37
|
signetAttestationMessage(context: __compactRuntime.CircuitContext<PS>,
|
|
43
38
|
requestId_0: Uint8Array,
|
|
44
39
|
serializedOutput_0: Uint8Array,
|
|
45
|
-
outputLen_0: bigint): Promise<__compactRuntime.CircuitResults<PS,
|
|
40
|
+
outputLen_0: bigint): Promise<__compactRuntime.CircuitResults<PS, Uint8Array>>;
|
|
46
41
|
assertHexOf(context: __compactRuntime.CircuitContext<PS>,
|
|
47
42
|
commitment_0: Uint8Array,
|
|
48
43
|
hexStr_0: Uint8Array): Promise<__compactRuntime.CircuitResults<PS, []>>;
|
|
49
44
|
assertPathCommitment(context: __compactRuntime.CircuitContext<PS>,
|
|
50
45
|
commitment_0: Uint8Array,
|
|
51
46
|
path_0: Uint8Array): Promise<__compactRuntime.CircuitResults<PS, []>>;
|
|
52
|
-
schnorrChallenge(context: __compactRuntime.CircuitContext<PS>,
|
|
53
|
-
ann_x_0: bigint,
|
|
54
|
-
ann_y_0: bigint,
|
|
55
|
-
pk_x_0: bigint,
|
|
56
|
-
pk_y_0: bigint,
|
|
57
|
-
msg_0: bigint[]): Promise<__compactRuntime.CircuitResults<PS, bigint>>;
|
|
58
47
|
}
|
|
59
48
|
|
|
60
49
|
export type Ledger = {
|