Euler's criterion
https://brilliant.org/wiki/eulers-criterion
https://proofwiki.org/wiki/Euler%27s_Criterion/Quadratic_Residue
https://mathweb.ucsd.edu/~apollack/8_305S_course_notes_quadratic_reciprocity.pdf
that an integer 'a' has a square root (aka is a quadratic residue) modulo a prime if a^((p-1)/2) ≡ 1 (mod p)
prime is ≡ 3 (mod 4)
r = ±a^((p+1)/4) (mod p)
prime is ≡ 5 (mod 8)
// alpha == (2*a)^((p-5)/8) mod p
// beta == 2*a*alpha^2 mod p is a square root of -1
// b == a*alpha*(beta-1) mod p is a square root of a
https://www.rfc-editor.org/rfc/rfc9380.html#section-6.6.2-4.2.2.2
https://link.springer.com/content/pdf/10.1007/978-3-642-14623-7_13.pdf
package aa
import (
"crypto/elliptic"
"fmt"
"math/big"
"testing"
)
func g(x, b, p *big.Int) *big.Int {
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
threeX := new(big.Int).Lsh(x, 1)
threeX.Add(threeX, x)
x3.Sub(x3, threeX)
x3.Add(x3, b)
x3.Mod(x3, p)
return x3
}
func findZ(i int64, c elliptic.Curve) int64 {
p := c.Params().P
b := c.Params().B
pm1 := new(big.Int).Sub(p, big.NewInt(1))
pm1.Rsh(pm1, 1)
for ; ; i-- {
t := big.NewInt(i)
t.Exp(t, pm1, p)
if t.Cmp(big.NewInt(1)) == 0 {
continue
}
t = big.NewInt(i * -3)
t.ModInverse(t, p)
t.Mul(t, b)
y := g(t, b, p)
y.Exp(y, pm1, p)
if y.Cmp(big.NewInt(1)) != 0 {
continue
}
return i
}
}
func hex(s string, base int) *big.Int {
r, _ := new(big.Int).SetString(s, base)
return r
}
var sm2 = &elliptic.CurveParams{
P: hex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16),
N: hex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16),
B: hex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16),
Gx: hex("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16),
Gy: hex("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16),
BitSize: 256,
Name: "sm2",
}
func TestZ(t *testing.T) {
c := sm2
r := int64(-1)
for i := 0; i < 9; i++ {
r--
r = findZ(r, c)
fmt.Println(r)
}
}