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 }