github.com/jimmyx0x/go-ethereum@v1.10.28/crypto/bn256/cloudflare/gfp_generic.go (about)

     1  //go:build (!amd64 && !arm64) || generic
     2  // +build !amd64,!arm64 generic
     3  
     4  package bn256
     5  
     6  func gfpCarry(a *gfP, head uint64) {
     7  	b := &gfP{}
     8  
     9  	var carry uint64
    10  	for i, pi := range p2 {
    11  		ai := a[i]
    12  		bi := ai - pi - carry
    13  		b[i] = bi
    14  		carry = (pi&^ai | (pi|^ai)&bi) >> 63
    15  	}
    16  	carry = carry &^ head
    17  
    18  	// If b is negative, then return a.
    19  	// Else return b.
    20  	carry = -carry
    21  	ncarry := ^carry
    22  	for i := 0; i < 4; i++ {
    23  		a[i] = (a[i] & carry) | (b[i] & ncarry)
    24  	}
    25  }
    26  
    27  func gfpNeg(c, a *gfP) {
    28  	var carry uint64
    29  	for i, pi := range p2 {
    30  		ai := a[i]
    31  		ci := pi - ai - carry
    32  		c[i] = ci
    33  		carry = (ai&^pi | (ai|^pi)&ci) >> 63
    34  	}
    35  	gfpCarry(c, 0)
    36  }
    37  
    38  func gfpAdd(c, a, b *gfP) {
    39  	var carry uint64
    40  	for i, ai := range a {
    41  		bi := b[i]
    42  		ci := ai + bi + carry
    43  		c[i] = ci
    44  		carry = (ai&bi | (ai|bi)&^ci) >> 63
    45  	}
    46  	gfpCarry(c, carry)
    47  }
    48  
    49  func gfpSub(c, a, b *gfP) {
    50  	t := &gfP{}
    51  
    52  	var carry uint64
    53  	for i, pi := range p2 {
    54  		bi := b[i]
    55  		ti := pi - bi - carry
    56  		t[i] = ti
    57  		carry = (bi&^pi | (bi|^pi)&ti) >> 63
    58  	}
    59  
    60  	carry = 0
    61  	for i, ai := range a {
    62  		ti := t[i]
    63  		ci := ai + ti + carry
    64  		c[i] = ci
    65  		carry = (ai&ti | (ai|ti)&^ci) >> 63
    66  	}
    67  	gfpCarry(c, carry)
    68  }
    69  
    70  func mul(a, b [4]uint64) [8]uint64 {
    71  	const (
    72  		mask16 uint64 = 0x0000ffff
    73  		mask32 uint64 = 0xffffffff
    74  	)
    75  
    76  	var buff [32]uint64
    77  	for i, ai := range a {
    78  		a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
    79  
    80  		for j, bj := range b {
    81  			b0, b2 := bj&mask32, bj>>32
    82  
    83  			off := 4 * (i + j)
    84  			buff[off+0] += a0 * b0
    85  			buff[off+1] += a1 * b0
    86  			buff[off+2] += a2*b0 + a0*b2
    87  			buff[off+3] += a3*b0 + a1*b2
    88  			buff[off+4] += a2 * b2
    89  			buff[off+5] += a3 * b2
    90  		}
    91  	}
    92  
    93  	for i := uint(1); i < 4; i++ {
    94  		shift := 16 * i
    95  
    96  		var head, carry uint64
    97  		for j := uint(0); j < 8; j++ {
    98  			block := 4 * j
    99  
   100  			xi := buff[block]
   101  			yi := (buff[block+i] << shift) + head
   102  			zi := xi + yi + carry
   103  			buff[block] = zi
   104  			carry = (xi&yi | (xi|yi)&^zi) >> 63
   105  
   106  			head = buff[block+i] >> (64 - shift)
   107  		}
   108  	}
   109  
   110  	return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
   111  }
   112  
   113  func halfMul(a, b [4]uint64) [4]uint64 {
   114  	const (
   115  		mask16 uint64 = 0x0000ffff
   116  		mask32 uint64 = 0xffffffff
   117  	)
   118  
   119  	var buff [18]uint64
   120  	for i, ai := range a {
   121  		a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
   122  
   123  		for j, bj := range b {
   124  			if i+j > 3 {
   125  				break
   126  			}
   127  			b0, b2 := bj&mask32, bj>>32
   128  
   129  			off := 4 * (i + j)
   130  			buff[off+0] += a0 * b0
   131  			buff[off+1] += a1 * b0
   132  			buff[off+2] += a2*b0 + a0*b2
   133  			buff[off+3] += a3*b0 + a1*b2
   134  			buff[off+4] += a2 * b2
   135  			buff[off+5] += a3 * b2
   136  		}
   137  	}
   138  
   139  	for i := uint(1); i < 4; i++ {
   140  		shift := 16 * i
   141  
   142  		var head, carry uint64
   143  		for j := uint(0); j < 4; j++ {
   144  			block := 4 * j
   145  
   146  			xi := buff[block]
   147  			yi := (buff[block+i] << shift) + head
   148  			zi := xi + yi + carry
   149  			buff[block] = zi
   150  			carry = (xi&yi | (xi|yi)&^zi) >> 63
   151  
   152  			head = buff[block+i] >> (64 - shift)
   153  		}
   154  	}
   155  
   156  	return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
   157  }
   158  
   159  func gfpMul(c, a, b *gfP) {
   160  	T := mul(*a, *b)
   161  	m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np)
   162  	t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2)
   163  
   164  	var carry uint64
   165  	for i, Ti := range T {
   166  		ti := t[i]
   167  		zi := Ti + ti + carry
   168  		T[i] = zi
   169  		carry = (Ti&ti | (Ti|ti)&^zi) >> 63
   170  	}
   171  
   172  	*c = gfP{T[4], T[5], T[6], T[7]}
   173  	gfpCarry(c, carry)
   174  }