@@ -81,3 +81,130 @@ func TestDepressedCubicRootFindsValidRoot(t *testing.T) {
8181 require .True (t , lhs .IsZero ())
8282 }
8383}
84+
85+ // cardanoDelta returns the dispatch discriminant delta = 108 - 27·c² used by
86+ // cardanoRoots to choose a branch (zero → repeatedRoots, non-square →
87+ // quadratic-extension branch, square → base-field branch).
88+ func cardanoDelta (c * extensions.E8 ) extensions.E8 {
89+ var c2 , delta extensions.E8
90+ c2 .Square (c )
91+ delta .Mul (& c2 , & e8TwentySeven )
92+ delta .Sub (& e8Neg4A3 , & delta )
93+ return delta
94+ }
95+
96+ func checkCubicRoots (t * testing.T , c extensions.E8 , roots []extensions.E8 ) {
97+ t .Helper ()
98+ require .NotEmpty (t , roots , "cardanoRoots returned no roots" )
99+ for _ , x := range roots {
100+ var lhs , x3 extensions.E8
101+ x3 .Square (& x ).Mul (& x3 , & x )
102+ lhs .Set (& x3 )
103+ lhs .Sub (& lhs , & x ).Sub (& lhs , & x ).Sub (& lhs , & x ).Add (& lhs , & c )
104+ require .True (t , lhs .IsZero (), "root does not satisfy x^3 - 3x + c = 0" )
105+ }
106+ }
107+
108+ // TestCardanoRepeatedRootBranch exercises the delta = 0 branch with c = 2:
109+ // x^3 - 3x + 2 = (x-1)^2 (x+2), so the dispatcher must hit repeatedRoots.
110+ func TestCardanoRepeatedRootBranch (t * testing.T ) {
111+ var c extensions.E8
112+ c .C0 .B0 .A0 .SetUint64 (2 )
113+
114+ delta := cardanoDelta (& c )
115+ require .True (t , delta .IsZero (), "c = 2 must drive delta to zero" )
116+
117+ roots := cardanoRoots (c )
118+ checkCubicRoots (t , c , roots )
119+
120+ var one , negTwo extensions.E8
121+ one .SetOne ()
122+ negTwo .SetOne ().Double (& negTwo ).Neg (& negTwo )
123+ var foundOne , foundNegTwo bool
124+ for _ , x := range roots {
125+ if x .Equal (& one ) {
126+ foundOne = true
127+ }
128+ if x .Equal (& negTwo ) {
129+ foundNegTwo = true
130+ }
131+ }
132+ require .True (t , foundOne , "repeated-root branch must produce x = 1" )
133+ require .True (t , foundNegTwo , "repeated-root branch must produce x = -2" )
134+ }
135+
136+ // TestCardanoBaseFieldBranch exercises the square-delta path. We build c from
137+ // a known root x in the prime subfield: c = 3x - x^3 guarantees that x solves
138+ // x^3 - 3x + c = 0, and any c whose components all lie in Fp produces a delta
139+ // that is a square in E8 (since [E8 : Fp] = 8 is even, every element of Fp is
140+ // a square in E8). Whether Cardano can recover roots through E8 depends on
141+ // whether the cube root needed by the formula lies in E8, so we search across
142+ // x values until the dispatcher returns a non-empty set including x.
143+ func TestCardanoBaseFieldBranch (t * testing.T ) {
144+ for n := uint64 (3 ); n < 10_000 ; n ++ {
145+ var x extensions.E8
146+ x .C0 .B0 .A0 .SetUint64 (n )
147+
148+ var c , x3 extensions.E8
149+ x3 .Square (& x ).Mul (& x3 , & x )
150+ c .Double (& x ).Add (& c , & x ).Sub (& c , & x3 )
151+
152+ delta := cardanoDelta (& c )
153+ if delta .IsZero () {
154+ continue
155+ }
156+ require .Equal (t , 1 , delta .Legendre (), "c in Fp must give a square delta in E8" )
157+
158+ roots := cardanoRoots (c )
159+ if len (roots ) == 0 {
160+ continue
161+ }
162+ checkCubicRoots (t , c , roots )
163+ var found bool
164+ for _ , r := range roots {
165+ if r .Equal (& x ) {
166+ found = true
167+ break
168+ }
169+ }
170+ if ! found {
171+ continue
172+ }
173+ return
174+ }
175+ t .Fatal ("could not find a base-field-branch witness in [3, 10000)" )
176+ }
177+
178+ // TestCardanoQuadraticExtensionBranch exercises the non-square-delta path.
179+ // To force delta to be a non-square in E8, c must have a non-trivial
180+ // extension component (any element of the prime subfield is a square in E8).
181+ // We construct x with both a base and an extension component, compute
182+ // c = 3x - x^3, and search for one whose delta is a non-square.
183+ func TestCardanoQuadraticExtensionBranch (t * testing.T ) {
184+ for n := uint64 (1 ); n < 4096 ; n ++ {
185+ var x extensions.E8
186+ x .C0 .B0 .A0 .SetUint64 (n )
187+ x .C1 .B0 .A0 .SetUint64 (1 )
188+
189+ var c , x3 extensions.E8
190+ x3 .Square (& x ).Mul (& x3 , & x )
191+ c .Double (& x ).Add (& c , & x ).Sub (& c , & x3 )
192+
193+ delta := cardanoDelta (& c )
194+ if delta .IsZero () || delta .Legendre () != - 1 {
195+ continue
196+ }
197+ roots := cardanoRoots (c )
198+ checkCubicRoots (t , c , roots )
199+ var found bool
200+ for _ , r := range roots {
201+ if r .Equal (& x ) {
202+ found = true
203+ break
204+ }
205+ }
206+ require .True (t , found , "extension branch must recover x at n = %d" , n )
207+ return
208+ }
209+ t .Fatal ("could not find a quadratic-extension-branch witness in [1, 4096)" )
210+ }
0 commit comments