@integraledger/lcp-binding-evm-common 0.14.0 → 0.15.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/CHANGELOG.md +40 -0
- package/dist/eip3009.d.ts +4 -3
- package/dist/eip3009.d.ts.map +1 -1
- package/dist/eip3009.js +25 -4
- package/dist/eip3009.js.map +1 -1
- package/package.json +5 -5
- package/src/eip3009.ts +25 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @integraledger/lcp-binding-evm-common
|
|
2
2
|
|
|
3
|
+
## 0.15.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1da6c07: `verifyEip3009Signature` threw on an attacker-chosen signature instead of answering `false`. Its docblock
|
|
8
|
+
promises the opposite — it "Answers `false` rather than throwing for the two UNTRUSTED inputs" — and a
|
|
9
|
+
seller pre-flighting an inbound x402 `PaymentPayload` was crashed by a hand-built 65-byte string that costs
|
|
10
|
+
no key, no chain and no funds to produce.
|
|
11
|
+
|
|
12
|
+
`isCanonicalSignature` checked shape, low-s and `v ∈ {27, 28}`, and not that `r` and `s` are in range.
|
|
13
|
+
Measured: `r=0x11…, s=0` threw, `r=0, s=0x11…` threw, and `r` at or above `n` threw. `"not-a-signature"`
|
|
14
|
+
was the only malformed shape the suite drove, and the regex already refused that — so every gate past the
|
|
15
|
+
regex was untested against a hostile value.
|
|
16
|
+
|
|
17
|
+
The range rules are the token's, on the same footing low-s is: `ecrecover` answers the ZERO ADDRESS rather
|
|
18
|
+
than reverting for `r = 0`, `s = 0` or a component at or above `n`, and OpenZeppelin's `ECRecover.recover`
|
|
19
|
+
— which `FiatTokenV2` routes through — reverts on the zero signer. `1 <= r < n` and `s !== 0` are now part
|
|
20
|
+
of the predicate. Low-s already caps `s` below `n/2`, so on the `s` side the only value the rule adds is
|
|
21
|
+
zero.
|
|
22
|
+
|
|
23
|
+
The gates went into the predicate rather than a `try` in the caller deliberately: a `try` would also swallow
|
|
24
|
+
an unencodable `typedData`, which is this deployment's own domain being wrong, and would tell an operator
|
|
25
|
+
with a mis-copied `tokenName` that every honest payer is a forger. That case still throws, as the head note
|
|
26
|
+
reserves.
|
|
27
|
+
- Updated dependencies [83ae16e]
|
|
28
|
+
- Updated dependencies [431b8ec]
|
|
29
|
+
- Updated dependencies [9c42f73]
|
|
30
|
+
- @integraledger/lcp-kernel@0.15.1
|
|
31
|
+
- @integraledger/lcp-binding-core@0.15.1
|
|
32
|
+
- @integraledger/lcp-authority@0.15.1
|
|
33
|
+
|
|
34
|
+
## 0.15.0
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- Updated dependencies [42fb196]
|
|
39
|
+
- @integraledger/lcp-kernel@0.15.0
|
|
40
|
+
- @integraledger/lcp-authority@0.15.0
|
|
41
|
+
- @integraledger/lcp-binding-core@0.15.0
|
|
42
|
+
|
|
3
43
|
## 0.14.0
|
|
4
44
|
|
|
5
45
|
### Patch Changes
|
package/dist/eip3009.d.ts
CHANGED
|
@@ -104,10 +104,11 @@ export interface LcpEvmSigner {
|
|
|
104
104
|
/**
|
|
105
105
|
* Whether the 65-byte signature is one `FiatTokenV2` will accept at all, before asking who signed it.
|
|
106
106
|
*
|
|
107
|
-
* Not a style check.
|
|
108
|
-
* turns {@link verifyEip3009Signature} from *"the chain will
|
|
107
|
+
* Not a style check. Every rule comes straight out of the token's `ECRecover.sol` and the `ecrecover`
|
|
108
|
+
* precompile beneath it, and skipping any one turns {@link verifyEip3009Signature} from *"the chain will
|
|
109
|
+
* accept this"* into *"some chain might"* — or, for the range rules, into a throw.
|
|
109
110
|
*
|
|
110
|
-
* ⭐ Exported so the
|
|
111
|
+
* ⭐ Exported so the boundaries are reachable by a test. `s === n/2` is ACCEPTED (the token's guard is
|
|
111
112
|
* `s > n/2`), and no signing run will ever produce that value — so an off-by-one there is invisible from
|
|
112
113
|
* the public predicate, where such a signature simply fails to recover and answers `false` either way.
|
|
113
114
|
*/
|
package/dist/eip3009.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip3009.d.ts","sourceRoot":"","sources":["../src/eip3009.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,GAAG,EAER,KAAK,eAAe,EACrB,MAAM,MAAM,CAAC;AAEd,qFAAqF;AACrF,eAAO,MAAM,gCAAgC;aAC3C,yBAAyB;iBACrB,IAAI,EAAE,MAAM;iBAAE,IAAI,EAAE,SAAS;;iBAC7B,IAAI,EAAE,IAAI;iBAAE,IAAI,EAAE,SAAS;;iBAC3B,IAAI,EAAE,OAAO;iBAAE,IAAI,EAAE,SAAS;;iBAC9B,IAAI,EAAE,YAAY;iBAAE,IAAI,EAAE,SAAS;;iBACnC,IAAI,EAAE,aAAa;iBAAE,IAAI,EAAE,SAAS;;iBACpC,IAAI,EAAE,OAAO;iBAAE,IAAI,EAAE,SAAS;;CAE1B,CAAC;AAEX;kFACkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;sGACsG;AACtG,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAMhD;AAED,gGAAgG;AAChG,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC;CACZ;AAED;;;mGAGmG;AACnG,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;sFAEsF;AACtF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,OAAO,gCAAgC,CAAC;IAC/C,WAAW,EAAE,2BAA2B,CAAC;IACzC,OAAO,EAAE;QACP,IAAI,EAAE,OAAO,CAAC;QACd,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,GAAG,CAAC;KACZ,CAAC;CACH,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,iBAAiB,GAAG;IAC3D,aAAa,EAAE,oBAAoB,CAAC;IACpC,SAAS,EAAE,gBAAgB,CAAC;CAC7B,CA+BA;AAED,qHAAqH;AACrH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,OAAO,EAAE;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"eip3009.d.ts","sourceRoot":"","sources":["../src/eip3009.ts"],"names":[],"mappings":"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"}
|
package/dist/eip3009.js
CHANGED
|
@@ -80,13 +80,25 @@ export function buildEip3009TypedData(i) {
|
|
|
80
80
|
* credential the chain refuses, and the seller has already served the resource by then.
|
|
81
81
|
*/
|
|
82
82
|
const SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
83
|
+
/**
|
|
84
|
+
* secp256k1's group order — the range `ecrecover` itself requires of `r` and `s`.
|
|
85
|
+
*
|
|
86
|
+
* ⛔ **The gate low-s does not cover, and the one a hostile counterparty reaches for.** `ecrecover` answers
|
|
87
|
+
* the ZERO ADDRESS rather than reverting for `r = 0`, `s = 0`, or either component at or above `n`, and
|
|
88
|
+
* OpenZeppelin's `ECRecover.recover` — which `FiatTokenV2` routes through — then reverts on the zero
|
|
89
|
+
* signer. These are refusals of the TOKEN on exactly the footing low-s is, so they belong in the same
|
|
90
|
+
* predicate rather than in a caller's `try`. Low-s already caps `s` below `n/2`, so on the `s` side the
|
|
91
|
+
* only value this rule adds is zero.
|
|
92
|
+
*/
|
|
93
|
+
const SECP256K1_N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
|
83
94
|
/**
|
|
84
95
|
* Whether the 65-byte signature is one `FiatTokenV2` will accept at all, before asking who signed it.
|
|
85
96
|
*
|
|
86
|
-
* Not a style check.
|
|
87
|
-
* turns {@link verifyEip3009Signature} from *"the chain will
|
|
97
|
+
* Not a style check. Every rule comes straight out of the token's `ECRecover.sol` and the `ecrecover`
|
|
98
|
+
* precompile beneath it, and skipping any one turns {@link verifyEip3009Signature} from *"the chain will
|
|
99
|
+
* accept this"* into *"some chain might"* — or, for the range rules, into a throw.
|
|
88
100
|
*
|
|
89
|
-
* ⭐ Exported so the
|
|
101
|
+
* ⭐ Exported so the boundaries are reachable by a test. `s === n/2` is ACCEPTED (the token's guard is
|
|
90
102
|
* `s > n/2`), and no signing run will ever produce that value — so an off-by-one there is invisible from
|
|
91
103
|
* the public predicate, where such a signature simply fails to recover and answers `false` either way.
|
|
92
104
|
*/
|
|
@@ -98,7 +110,16 @@ export function isCanonicalSignature(signature) {
|
|
|
98
110
|
const parts = /^0x([0-9a-fA-F]{64})([0-9a-fA-F]{64})([0-9a-fA-F]{2})$/.exec(signature);
|
|
99
111
|
if (parts === null)
|
|
100
112
|
return false;
|
|
101
|
-
|
|
113
|
+
const r = BigInt(`0x${parts[1]}`);
|
|
114
|
+
const s = BigInt(`0x${parts[2]}`);
|
|
115
|
+
// RANGE before malleability. `1 <= r < n` and `s !== 0`: outside these the recovery does not merely
|
|
116
|
+
// yield the wrong answer, it raises — which is how an attacker-chosen 65 bytes, costing no key, no
|
|
117
|
+
// chain and no funds, crashed a seller pre-flighting an inbound payload instead of being refused.
|
|
118
|
+
if (r === 0n || r >= SECP256K1_N)
|
|
119
|
+
return false;
|
|
120
|
+
if (s === 0n)
|
|
121
|
+
return false;
|
|
122
|
+
if (s > SECP256K1_HALF_N)
|
|
102
123
|
return false;
|
|
103
124
|
const v = Number.parseInt(parts[3], 16);
|
|
104
125
|
return v === 27 || v === 28;
|
package/dist/eip3009.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip3009.js","sourceRoot":"","sources":["../src/eip3009.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAEL,UAAU,EAEV,uBAAuB,GAExB,MAAM,MAAM,CAAC;AAEd,qFAAqF;AACrF,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,yBAAyB,EAAE;QACzB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;QACjC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;QAC/B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;QAClC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE;QACvC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE;QACxC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;KACnC;CACO,CAAC;AAEX;kFACkF;AAClF,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,CAAC;QACJ,MAAM,IAAI,KAAK,CAAC,+CAA+C,OAAO,GAAG,CAAC,CAAC;IAC7E,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAED;sGACsG;AACtG,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,4FAA4F,KAAK,GAAG,CACrG,CAAC;IACJ,OAAO,KAAK,CAAC,WAAW,EAAS,CAAC;AACpC,CAAC;AAoDD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAoB;IAIxD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5B,MAAM,aAAa,GAAyB;QAC1C,IAAI;QACJ,EAAE;QACF,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,KAAK;KACN,CAAC;IACF,MAAM,SAAS,GAAqB;QAClC,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,CAAC,SAAS;YACjB,OAAO,EAAE,CAAC,CAAC,YAAY;YACvB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC;SACnD;QACD,KAAK,EAAE,gCAAgC;QACvC,WAAW,EAAE,2BAA2B;QACxC,OAAO,EAAE;YACP,IAAI;YACJ,EAAE;YACF,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YACtB,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;YAChC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;YAClC,KAAK;SACN;KACF,CAAC;IACF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;AACtC,CAAC;AAaD;;;;;;;;GAQG;AACH,MAAM,gBAAgB,GACpB,mEAAmE,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,gGAAgG;IAChG,mGAAmG;IACnG,uGAAuG;IACvG,oFAAoF;IACpF,MAAM,KAAK,GAAG,wDAAwD,CAAC,IAAI,CACzE,SAAS,CACV,CAAC;IACF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,
|
|
1
|
+
{"version":3,"file":"eip3009.js","sourceRoot":"","sources":["../src/eip3009.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integraledger/lcp-binding-evm-common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Shared EVM machinery for LCP rail bindings: typed-data construction and signature verification.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lcp",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
},
|
|
44
44
|
"homepage": "https://github.com/IntegraLedger/integra-protocol/tree/main/packages/binding-evm-common#readme",
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"
|
|
47
|
-
"@integraledger/lcp-
|
|
48
|
-
"@integraledger/lcp-
|
|
49
|
-
"
|
|
46
|
+
"@integraledger/lcp-authority": "0.15.1",
|
|
47
|
+
"@integraledger/lcp-binding-core": "0.15.1",
|
|
48
|
+
"@integraledger/lcp-kernel": "0.15.1",
|
|
49
|
+
"viem": "2.55.19"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "24.13.3",
|
package/src/eip3009.ts
CHANGED
|
@@ -159,13 +159,27 @@ export interface LcpEvmSigner {
|
|
|
159
159
|
const SECP256K1_HALF_N =
|
|
160
160
|
0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* secp256k1's group order — the range `ecrecover` itself requires of `r` and `s`.
|
|
164
|
+
*
|
|
165
|
+
* ⛔ **The gate low-s does not cover, and the one a hostile counterparty reaches for.** `ecrecover` answers
|
|
166
|
+
* the ZERO ADDRESS rather than reverting for `r = 0`, `s = 0`, or either component at or above `n`, and
|
|
167
|
+
* OpenZeppelin's `ECRecover.recover` — which `FiatTokenV2` routes through — then reverts on the zero
|
|
168
|
+
* signer. These are refusals of the TOKEN on exactly the footing low-s is, so they belong in the same
|
|
169
|
+
* predicate rather than in a caller's `try`. Low-s already caps `s` below `n/2`, so on the `s` side the
|
|
170
|
+
* only value this rule adds is zero.
|
|
171
|
+
*/
|
|
172
|
+
const SECP256K1_N =
|
|
173
|
+
0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
|
174
|
+
|
|
162
175
|
/**
|
|
163
176
|
* Whether the 65-byte signature is one `FiatTokenV2` will accept at all, before asking who signed it.
|
|
164
177
|
*
|
|
165
|
-
* Not a style check.
|
|
166
|
-
* turns {@link verifyEip3009Signature} from *"the chain will
|
|
178
|
+
* Not a style check. Every rule comes straight out of the token's `ECRecover.sol` and the `ecrecover`
|
|
179
|
+
* precompile beneath it, and skipping any one turns {@link verifyEip3009Signature} from *"the chain will
|
|
180
|
+
* accept this"* into *"some chain might"* — or, for the range rules, into a throw.
|
|
167
181
|
*
|
|
168
|
-
* ⭐ Exported so the
|
|
182
|
+
* ⭐ Exported so the boundaries are reachable by a test. `s === n/2` is ACCEPTED (the token's guard is
|
|
169
183
|
* `s > n/2`), and no signing run will ever produce that value — so an off-by-one there is invisible from
|
|
170
184
|
* the public predicate, where such a signature simply fails to recover and answers `false` either way.
|
|
171
185
|
*/
|
|
@@ -178,7 +192,14 @@ export function isCanonicalSignature(signature: string): boolean {
|
|
|
178
192
|
signature,
|
|
179
193
|
);
|
|
180
194
|
if (parts === null) return false;
|
|
181
|
-
|
|
195
|
+
const r = BigInt(`0x${parts[1] as string}`);
|
|
196
|
+
const s = BigInt(`0x${parts[2] as string}`);
|
|
197
|
+
// RANGE before malleability. `1 <= r < n` and `s !== 0`: outside these the recovery does not merely
|
|
198
|
+
// yield the wrong answer, it raises — which is how an attacker-chosen 65 bytes, costing no key, no
|
|
199
|
+
// chain and no funds, crashed a seller pre-flighting an inbound payload instead of being refused.
|
|
200
|
+
if (r === 0n || r >= SECP256K1_N) return false;
|
|
201
|
+
if (s === 0n) return false;
|
|
202
|
+
if (s > SECP256K1_HALF_N) return false;
|
|
182
203
|
const v = Number.parseInt(parts[3] as string, 16);
|
|
183
204
|
return v === 27 || v === 28;
|
|
184
205
|
}
|