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  }