github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/crypto/bn256/cloudflare/gfp_generic.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  // +build !amd64,!arm64 generic
    19  
    20  package bn256
    21  
    22  func gfpCarry(a *gfP, head uint64) {
    23  	b := &gfP{}
    24  
    25  	var carry uint64
    26  	for i, pi := range p2 {
    27  		ai := a[i]
    28  		bi := ai - pi - carry
    29  		b[i] = bi
    30  		carry = (pi&^ai | (pi|^ai)&bi) >> 63
    31  	}
    32  	carry = carry &^ head
    33  
    34  	// If b is negative, then return a.
    35  	// Else return b.
    36  	carry = -carry
    37  	ncarry := ^carry
    38  	for i := 0; i < 4; i++ {
    39  		a[i] = (a[i] & carry) | (b[i] & ncarry)
    40  	}
    41  }
    42  
    43  func gfpNeg(c, a *gfP) {
    44  	var carry uint64
    45  	for i, pi := range p2 {
    46  		ai := a[i]
    47  		ci := pi - ai - carry
    48  		c[i] = ci
    49  		carry = (ai&^pi | (ai|^pi)&ci) >> 63
    50  	}
    51  	gfpCarry(c, 0)
    52  }
    53  
    54  func gfpAdd(c, a, b *gfP) {
    55  	var carry uint64
    56  	for i, ai := range a {
    57  		bi := b[i]
    58  		ci := ai + bi + carry
    59  		c[i] = ci
    60  		carry = (ai&bi | (ai|bi)&^ci) >> 63
    61  	}
    62  	gfpCarry(c, carry)
    63  }
    64  
    65  func gfpSub(c, a, b *gfP) {
    66  	t := &gfP{}
    67  
    68  	var carry uint64
    69  	for i, pi := range p2 {
    70  		bi := b[i]
    71  		ti := pi - bi - carry
    72  		t[i] = ti
    73  		carry = (bi&^pi | (bi|^pi)&ti) >> 63
    74  	}
    75  
    76  	carry = 0
    77  	for i, ai := range a {
    78  		ti := t[i]
    79  		ci := ai + ti + carry
    80  		c[i] = ci
    81  		carry = (ai&ti | (ai|ti)&^ci) >> 63
    82  	}
    83  	gfpCarry(c, carry)
    84  }
    85  
    86  func mul(a, b [4]uint64) [8]uint64 {
    87  	const (
    88  		mask16 uint64 = 0x0000ffff
    89  		mask32 uint64 = 0xffffffff
    90  	)
    91  
    92  	var buff [32]uint64
    93  	for i, ai := range a {
    94  		a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
    95  
    96  		for j, bj := range b {
    97  			b0, b2 := bj&mask32, bj>>32
    98  
    99  			off := 4 * (i + j)
   100  			buff[off+0] += a0 * b0
   101  			buff[off+1] += a1 * b0
   102  			buff[off+2] += a2*b0 + a0*b2
   103  			buff[off+3] += a3*b0 + a1*b2
   104  			buff[off+4] += a2 * b2
   105  			buff[off+5] += a3 * b2
   106  		}
   107  	}
   108  
   109  	for i := uint(1); i < 4; i++ {
   110  		shift := 16 * i
   111  
   112  		var head, carry uint64
   113  		for j := uint(0); j < 8; j++ {
   114  			block := 4 * j
   115  
   116  			xi := buff[block]
   117  			yi := (buff[block+i] << shift) + head
   118  			zi := xi + yi + carry
   119  			buff[block] = zi
   120  			carry = (xi&yi | (xi|yi)&^zi) >> 63
   121  
   122  			head = buff[block+i] >> (64 - shift)
   123  		}
   124  	}
   125  
   126  	return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
   127  }
   128  
   129  func halfMul(a, b [4]uint64) [4]uint64 {
   130  	const (
   131  		mask16 uint64 = 0x0000ffff
   132  		mask32 uint64 = 0xffffffff
   133  	)
   134  
   135  	var buff [18]uint64
   136  	for i, ai := range a {
   137  		a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
   138  
   139  		for j, bj := range b {
   140  			if i+j > 3 {
   141  				break
   142  			}
   143  			b0, b2 := bj&mask32, bj>>32
   144  
   145  			off := 4 * (i + j)
   146  			buff[off+0] += a0 * b0
   147  			buff[off+1] += a1 * b0
   148  			buff[off+2] += a2*b0 + a0*b2
   149  			buff[off+3] += a3*b0 + a1*b2
   150  			buff[off+4] += a2 * b2
   151  			buff[off+5] += a3 * b2
   152  		}
   153  	}
   154  
   155  	for i := uint(1); i < 4; i++ {
   156  		shift := 16 * i
   157  
   158  		var head, carry uint64
   159  		for j := uint(0); j < 4; j++ {
   160  			block := 4 * j
   161  
   162  			xi := buff[block]
   163  			yi := (buff[block+i] << shift) + head
   164  			zi := xi + yi + carry
   165  			buff[block] = zi
   166  			carry = (xi&yi | (xi|yi)&^zi) >> 63
   167  
   168  			head = buff[block+i] >> (64 - shift)
   169  		}
   170  	}
   171  
   172  	return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
   173  }
   174  
   175  func gfpMul(c, a, b *gfP) {
   176  	T := mul(*a, *b)
   177  	m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np)
   178  	t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2)
   179  
   180  	var carry uint64
   181  	for i, Ti := range T {
   182  		ti := t[i]
   183  		zi := Ti + ti + carry
   184  		T[i] = zi
   185  		carry = (Ti&ti | (Ti|ti)&^zi) >> 63
   186  	}
   187  
   188  	*c = gfP{T[4], T[5], T[6], T[7]}
   189  	gfpCarry(c, carry)
   190  }