github.com/consensys/gnark-crypto@v0.14.0/field/generator/config/extension.go (about) 1 package config 2 3 import "math/big" 4 5 type Element []big.Int 6 7 // Extension is a simple radical extension, obtained by adjoining ⁿ√α to Fp 8 type Extension struct { 9 Base *FieldConfig //Fp 10 Size big.Int //q 11 Degree int //n such that q = pⁿ TODO: Make uint8 so forced to be positive and small 12 RootOf int64 //α 13 } 14 15 func NewTower(base *FieldConfig, degree uint8, rootOf int64) Extension { 16 ret := Extension{ 17 Degree: int(degree), 18 RootOf: rootOf, 19 Base: base, 20 } 21 ret.Size.Exp(base.ModulusBig, big.NewInt(int64(degree)), nil) 22 return ret 23 } 24 25 func (f *Extension) FromInt64(i ...int64) Element { 26 z := make(Element, f.Degree) 27 for n := 0; n < len(i) && n < int(f.Degree); n++ { 28 z[n].SetInt64(i[n]) 29 } 30 return z 31 } 32 33 func (f *Extension) Neg(x Element) Element { 34 z := make(Element, len(x)) 35 for n := 0; n < len(x); n++ { 36 z[n].Neg(&x[n]) 37 } 38 return z 39 } 40 41 func max(x int, y int) int { 42 if x > y { 43 return x 44 } 45 return y 46 } 47 48 func (f *Extension) Add(x Element, y Element) Element { 49 z := make(Element, f.Degree) 50 51 for i := 0; i < f.Degree; i++ { 52 z[i]. 53 Add(&x[i], &y[i]). 54 Mod(&z[i], f.Base.ModulusBig) 55 } 56 return z 57 } 58 59 func (f *Extension) Mul(x Element, y Element) Element { 60 z := make(Element, f.Degree) 61 maxP := len(x) + len(y) - 2 62 alpha := big.NewInt(f.RootOf) 63 64 for p := maxP; p >= 0; p-- { 65 66 var rp big.Int 67 68 for m := max(p-(len(y)-1), 0); m < len(x) && m <= p; m++ { 69 n := p - m 70 var prod big.Int 71 prod.Mul(&x[m], &y[n]) 72 rp.Add(&rp, &prod) 73 } 74 75 rI := p % int(f.Degree) //reduced index 76 77 z[rI].Add(&z[rI], &rp).Mod(&z[rI], f.Base.ModulusBig) 78 79 if p >= int(f.Degree) { 80 z[rI].Mul(&z[rI], alpha) 81 } 82 } 83 84 return z 85 } 86 87 func (f *Extension) MulScalar(c *big.Int, x Element) Element { 88 z := make(Element, len(x)) 89 for i := 0; i < len(x); i++ { 90 f.Base.Mul(&z[i], c, &x[i]) 91 } 92 return z 93 } 94 95 func (f *Extension) Halve(z Element) { 96 for i := 0; i < len(z); i++ { 97 if z[i].Bit(0) != 0 { 98 z[i].Add(&z[i], f.Base.ModulusBig) 99 } 100 z[i].Rsh(&z[i], 1) 101 } 102 } 103 104 func (f *Extension) reduce(z Element) { 105 for i := 0; i < len(z); i++ { 106 z[i].Mod(&z[i], f.Base.ModulusBig) 107 } 108 } 109 110 // Sqrt returning √ x, or nil if x is not qr. 111 func (f *Extension) Sqrt(x Element) Element { 112 113 z := make(Element, f.Degree) 114 switch f.Degree { 115 case 1: 116 if z[0].ModSqrt(&x[0], f.Base.ModulusBig) == nil { 117 return nil 118 } 119 case 2: 120 // z = z₀ + z₁ i 121 122 if x[0].BitLen() == 0 { 123 z[1].ModInverse(big.NewInt(f.RootOf), f.Base.ModulusBig).Mul(&z[1], &x[1]) 124 } 125 126 var discriminant big.Int 127 z[0].Mul(&x[0], &x[0]) 128 z[1].Mul(&x[1], &x[1]).Mul(&z[1], big.NewInt(-f.RootOf)) 129 z[0].Sub(&z[0], &z[1]) 130 if discriminant.ModSqrt(&z[0], f.Base.ModulusBig) == nil { 131 return nil 132 } 133 z[0].Add(&x[0], &discriminant) 134 f.Base.halve(&z[0], &z[0]) 135 if z[0].ModSqrt(&z[0], f.Base.ModulusBig) == nil { 136 z[0].Sub(&z[0], &discriminant) 137 if z[0].ModSqrt(&z[0], f.Base.ModulusBig) == nil { 138 return nil 139 } 140 } 141 z[1].Lsh(&z[0], 1).ModInverse(&z[1], f.Base.ModulusBig).Mul(&z[1], &x[1]) 142 143 default: 144 panic("only degrees 1 and 2 are supported") 145 } 146 147 f.reduce(z) 148 return z 149 } 150 151 func (f *Extension) ToMont(x Element) Element { 152 z := make([]big.Int, len(x)) 153 for i := 0; i < len(x); i++ { 154 z[i] = f.Base.ToMont(x[i]) 155 } 156 return z 157 } 158 159 func (f *Extension) Equal(x Element, y Element) bool { 160 if len(x) != len(y) { 161 return false 162 } 163 for i := 0; i < len(x); i++ { 164 var diff big.Int 165 if diff.Sub(&x[i], &y[i]).Mod(&diff, f.Base.ModulusBig).BitLen() != 0 { 166 return false 167 } 168 } 169 return true 170 } 171 172 func (f *Extension) norm(z *big.Int, x Element) *Extension { 173 if f.Degree != 2 { 174 panic("only degree 2 supported") 175 } 176 var x0Sq big.Int 177 178 x0Sq.Mul(&x[0], &x[0]) 179 180 res := big.NewInt(-f.RootOf) 181 res.Mul(res, &x[1]).Mul(res, &x[1]).Add(res, &x0Sq) 182 183 z.Set(res) 184 185 return f 186 } 187 188 func (f *Extension) Inverse(x Element) Element { 189 z := make(Element, f.Degree) 190 switch f.Degree { 191 case 1: 192 z[0].ModInverse(&x[0], f.Base.ModulusBig) 193 case 2: 194 var normInv big.Int 195 f.norm(&normInv, x) 196 normInv.ModInverse(&normInv, f.Base.ModulusBig) 197 z[0].Mul(&x[0], &normInv) 198 199 z[1].Neg(&x[1]).Mul(&z[1], &normInv) 200 default: 201 panic("can't invert in extensions of degree > 2") 202 } 203 return z 204 } 205 206 func (f *Extension) Exp(x Element, exp *big.Int) Element { 207 208 if exp.BitLen() == 0 { 209 return f.FromInt64(1) 210 } 211 212 z := x 213 214 for i := exp.BitLen() - 2; i >= 0; i-- { 215 z = f.Mul(z, z) 216 if exp.Bit(i) == 1 { 217 z = f.Mul(z, x) 218 } 219 } 220 221 return z 222 } 223 224 // Div returns u/v 225 func (f *Extension) Div(u, v Element) Element { 226 return f.Mul(u, f.Inverse(v)) 227 } 228 229 func (f *Extension) IsZero(u Element) bool { 230 for i := 0; i < len(u); i++ { 231 if u[i].BitLen() != 0 { 232 return false 233 } 234 } 235 return true 236 } 237 238 func NewElement(s []string) []big.Int { 239 res := make([]big.Int, len(s)) 240 for i, S := range s { 241 res[i].SetString(S, 0) 242 } 243 return res 244 }