Skip to content

Commit 4b2907d

Browse files
authored
feat(tests): add tests for P256 with x,y out of range (#2237)
Add better test cases for the `p256verify` precompile where `x` or `y` coordinate of the public key point are incorrectly bigger than `P`. The difference from the previous similar cases is that reducing the invalid values by `P` creates a valid signature. The reduction can happen unintentionally by converting values to the Montgomery form.
1 parent 3c7d37b commit 4b2907d

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Find points on P256 with low x or y coordinates by solving the curve equation
2+
# independently for range of low x and y values.
3+
#
4+
# Can be executed online: https://sagecell.sagemath.org/?q=pmqnkn
5+
#
6+
# Test cases generated:
7+
#
8+
# x_0_y_positive:
9+
# (0x0000000000000000000000000000000000000000000000000000000000000000, 0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4)
10+
# x_0_y_negative:
11+
# (0x0000000000000000000000000000000000000000000000000000000000000000, 0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b)
12+
# x_5_y_positive:
13+
# x_P_plus_5_y_positive:
14+
# (0x0000000000000000000000000000000000000000000000000000000000000005, 0x459243b9aa581806fe913bce99817ade11ca503c64d9a3c533415c083248fbcc)
15+
# x_5_y_negative:
16+
# x_P_plus_5_y_negative:
17+
# (0x0000000000000000000000000000000000000000000000000000000000000005, 0xba6dbc4555a7e7fa016ec431667e8521ee35afc49b265c3accbea3f7cdb70433)
18+
# y_1:
19+
# y_P_plus_1:
20+
# (0x09e78d4ef60d05f750f6636209092bc43cbdd6b47e11a9de20a9feb2a50bb96c, 0x0000000000000000000000000000000000000000000000000000000000000001)
21+
22+
23+
p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
24+
a = -3
25+
b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
26+
27+
F = GF(p)
28+
aF = F(a)
29+
bF = F(b)
30+
31+
M = 11
32+
33+
for x_int in range(0, M):
34+
print(f"x = {x_int}:")
35+
xF = F(x_int)
36+
rhs = xF**3 + aF*xF + bF
37+
38+
if rhs.is_square():
39+
y = rhs.sqrt()
40+
for yF in [y, -y]:
41+
print(f" (0x{int(xF):064x}, 0x{int(yF):064x})")
42+
43+
R.<x> = PolynomialRing(F)
44+
for y_int in range(0, M):
45+
yF = F(y_int)
46+
# Solve x^3 + a*x + (b - y^2) == 0 over F_p
47+
c = bF - yF * yF
48+
f = x^3 + aF * x + c
49+
50+
roots = [r for (r, mult) in f.roots()] # distinct roots over F_p
51+
52+
print(f"y = {y_int}:")
53+
for xF in sorted(roots):
54+
print(f" (0x{int(xF):064x}, 0x{y_int:064x})")

tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,38 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t
156156
+ Y(0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B),
157157
id="x_0_y_negative",
158158
),
159+
pytest.param(
160+
H(0x5F95DCD6E41662D1E0AEFCCDB7877877C1FD88C9E67FC3CDA0D1D520FA8A3AC2)
161+
+ R(0xAF5DFDDB7EDC789D7C9C42A44AFBBF13C8F1D77D576B6EE5F11FEA4F33E2CB39)
162+
+ S(0xA28F8C5625AD622950F2FCE9672784B287EF9E032ADE8C23BA218413A1CF6522)
163+
+ X(5)
164+
+ Y(0x459243B9AA581806FE913BCE99817ADE11CA503C64D9A3C533415C083248FBCC),
165+
id="x_5_y_positive",
166+
),
167+
pytest.param(
168+
H(0x31CE0B00FA8DD61EF28C7DC5F839C78CF70D60E625E0670BF9C9FCE25E89D99F)
169+
+ R(0x0FA19CBE154513BA348F2DB951AFB6E135BAC5BD8891282781A032103C3F1289)
170+
+ S(0xD9ABF5C4E61098A6E653F265770BDBA36ECC8073CEF99548D89FE2C39A7AFA9B)
171+
+ X(5)
172+
+ Y(0xBA6DBC4555A7E7FA016EC431667E8521EE35AFC49B265C3ACCBEA3F7CDB70433),
173+
id="x_5_y_negative",
174+
),
175+
pytest.param(
176+
H(0x65B0E03E7A27E6F9F4989C72486FCAF0A3ECF3EF60D14F1C11FB5BF071A8FD1B)
177+
+ R(0x0B0CC9E314E4180FE18D205010DD1C4410632D472CC4E7AB56CBC04091ABE006)
178+
+ S(0x8D12C4F19AC41D7877705453A247AB96394E7C093F57EC073A9D150CDE6B68C6)
179+
+ X(0x09E78D4EF60D05F750F6636209092BC43CBDD6B47E11A9DE20A9FEB2A50BB96C)
180+
+ Y(1),
181+
id="y_1",
182+
),
183+
pytest.param(
184+
H(0x744084AD41EE67ED1802A6868ACE7815FD6FC0585A3479FF68E69ADB8DD2B420)
185+
+ R(0xB481C7650CBE85BCD15565811966DA2DA4E4E2931F0892D911520B6A06C340D8)
186+
+ S(0xE4C2D9FB9A4E3E29B7414F0408B2EBC4421D5BC8ADDCCF864AFF9E7E10DA31BB)
187+
+ X(0x09E78D4EF60D05F750F6636209092BC43CBDD6B47E11A9DE20A9FEB2A50BB96C)
188+
+ Y(Spec.P - 1),
189+
id="y_P_minus_1",
190+
),
159191
# Test case for u1==u2 and Q==G.
160192
# This test case is important because u1*G + u2*Q is point doubling.
161193
pytest.param(
@@ -344,6 +376,46 @@ def test_valid(state_test: StateTestFiller, pre: Alloc, post: dict, tx: Transact
344376
Spec.H0 + Spec.R0 + Spec.S0 + X(Spec.P + 1) + Spec.Y0,
345377
id="x_greater_than_p",
346378
),
379+
pytest.param(
380+
H(0xC3D3BE9EB3577F217AE0AB360529A30B18ADC751AEC886328593D7D6FE042809)
381+
+ R(0x3A4E97B44CBF88B90E6205A45BA957E520F63F3C6072B53C244653278A1819D8)
382+
+ S(0x6A184AA037688A5EBD25081FD2C0B10BB64FA558B671BD81955CA86E09D9D722)
383+
+ X(Spec.P) # Valid for X(0)
384+
+ Y(0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4),
385+
id="x_P_y_positive",
386+
),
387+
pytest.param(
388+
H(0xF98A88895CB0866C5BAD58CF03000DDF9D21CB9407892FF54D637E6A046AFBB3)
389+
+ R(0x81DC074973D3222F3930981AD98D022517C91063FFB83CFD620E29B86DC30A8F)
390+
+ S(0x365E4CD085617A265765062A2D9954ED86309DFA33CF5AE1464FE119419FC34A)
391+
+ X(Spec.P) # Valid for X(0)
392+
+ Y(0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B),
393+
id="x_P_y_negative",
394+
),
395+
pytest.param(
396+
H(0x5F95DCD6E41662D1E0AEFCCDB7877877C1FD88C9E67FC3CDA0D1D520FA8A3AC2)
397+
+ R(0xAF5DFDDB7EDC789D7C9C42A44AFBBF13C8F1D77D576B6EE5F11FEA4F33E2CB39)
398+
+ S(0xA28F8C5625AD622950F2FCE9672784B287EF9E032ADE8C23BA218413A1CF6522)
399+
+ X(Spec.P + 5) # Valid for X(5)
400+
+ Y(0x459243B9AA581806FE913BCE99817ADE11CA503C64D9A3C533415C083248FBCC),
401+
id="x_P_plus_5_y_positive",
402+
),
403+
pytest.param(
404+
H(0x31CE0B00FA8DD61EF28C7DC5F839C78CF70D60E625E0670BF9C9FCE25E89D99F)
405+
+ R(0x0FA19CBE154513BA348F2DB951AFB6E135BAC5BD8891282781A032103C3F1289)
406+
+ S(0xD9ABF5C4E61098A6E653F265770BDBA36ECC8073CEF99548D89FE2C39A7AFA9B)
407+
+ X(Spec.P + 5) # Valid for X(5)
408+
+ Y(0xBA6DBC4555A7E7FA016EC431667E8521EE35AFC49B265C3ACCBEA3F7CDB70433),
409+
id="x_P_plus_5_y_negative",
410+
),
411+
pytest.param(
412+
H(0x65B0E03E7A27E6F9F4989C72486FCAF0A3ECF3EF60D14F1C11FB5BF071A8FD1B)
413+
+ R(0x0B0CC9E314E4180FE18D205010DD1C4410632D472CC4E7AB56CBC04091ABE006)
414+
+ S(0x8D12C4F19AC41D7877705453A247AB96394E7C093F57EC073A9D150CDE6B68C6)
415+
+ X(0x09E78D4EF60D05F750F6636209092BC43CBDD6B47E11A9DE20A9FEB2A50BB96C)
416+
+ Y(Spec.P + 1), # Valid for Y(1)
417+
id="y_P_plus_1",
418+
),
347419
# Test case produces the point R at infinity: (R0/S0)*G + (R0/S0)*(-G).
348420
pytest.param(
349421
H(Spec.R0.value) + Spec.R0 + Spec.S0 + X(Spec.Gx) + Y(Spec.P - Spec.Gy),

0 commit comments

Comments
 (0)