*/
import { base } from './base'
import { base2 } from './base2'
-import { FieldElement, fe, fe_1, fe_add, fe_cmov, fe_frombytes, fe_isnegative, fe_iszero, fe_memcmov, fe_memcopy, fe_memneg, fe_mul, fe_neg, fe_pow22523, fe_sq, fe_sub } from './fe'
+import { FieldElement, fe, fe_1, fe_add, fe_cmov, fe_frombytes, fe_isnegative, fe_iszero, fe_mul, fe_neg, fe_pow22523, fe_sq, fe_sub } from './fe'
import { ge_add_cached, ge_add_precomp, ge_cached, ge_p1p1, ge_p1p1_0, ge_p1p1_to_p2, ge_p1p1_to_p3, ge_p2, ge_p2_0, ge_p2_dbl, ge_p2_to_p3, ge_p3, ge_p3_0, ge_p3_dbl, ge_p3_to_cached, ge_p3_tobytes, ge_precomp, ge_precomp_0, ge_sub_cached, ge_sub_precomp } from './p'
/**
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116, 0, 0
])
-/** Scratch array equivalent to a `ge_precomp`: 3x 12-limb FieldElements */
-const minust = new StaticArray<i32>(36)
//@ts-expect-error
@inline
function ge_cmov8_base (t: ge_precomp, bp: usize, b: i8): void {
- const bnegative: i8 = b >> 7 /* retains only the sign bit of `b` */
- const babs: i8 = b - (((-bnegative) & b) * (i8(1) << 1))
+ const isbneg: i8 = (b >> 7) & 1 /* 0: positive; 1: negative */
+ const babs: i8 = b - (((-isbneg) & b) * (i8(1) << 1))
- ge_precomp_0(t)
+ // identity: (1, 1, 0)
+ // yplusx = 1
+ let p0 = i32x4(1, 0, 0, 0), p1 = i32x4(0, 0, 0, 0), p2 = i32x4(0, 0, 0, 0)
+ // yminusx = 1
+ let m0 = i32x4(1, 0, 0, 0), m1 = i32x4(0, 0, 0, 0), m2 = i32x4(0, 0, 0, 0)
+ // xy2d = 0
+ let d0 = i32x4(0, 0, 0, 0), d1 = i32x4(0, 0, 0, 0), d2 = i32x4(0, 0, 0, 0)
// base pointer offset += 144n = (4 bytes * 12 values * 3 fields) * n
- // for values 1..8, conditionally move if `abs(b)` equals the current index
for (let i: i8 = 1; i <= 8; i++, bp += 144) {
- const iEqualsBabs: i8 = ((babs ^ i) - 1) >> 7 /* xor == 0: yes */
- fe_memcmov(changetype<usize>(t.yplusx), bp, iEqualsBabs)
- fe_memcmov(changetype<usize>(t.yminusx), bp + 48, iEqualsBabs)
- fe_memcmov(changetype<usize>(t.xy2d), bp + 96, iEqualsBabs)
+ const isbabs: i8 = (((babs ^ i) - 1) >> 7) & 1 /* xor == 0: yes; xor == 1..255: no */
+ const c = v128.splat<u64>(0 - u64(isbabs))
+ p0 = v128.bitselect(v128.load(bp), p0, c)
+ p1 = v128.bitselect(v128.load(bp, 16), p1, c)
+ p2 = v128.bitselect(v128.load(bp, 32), p2, c)
+ m0 = v128.bitselect(v128.load(bp, 48), m0, c)
+ m1 = v128.bitselect(v128.load(bp, 64), m1, c)
+ m2 = v128.bitselect(v128.load(bp, 80), m2, c)
+ d0 = v128.bitselect(v128.load(bp, 96), d0, c)
+ d1 = v128.bitselect(v128.load(bp, 112), d1, c)
+ d2 = v128.bitselect(v128.load(bp, 128), d2, c)
}
- fe_memcopy(changetype<usize>(minust), changetype<usize>(t.yminusx))
- fe_memcopy(changetype<usize>(minust) + 48, changetype<usize>(t.yplusx))
- fe_memneg(changetype<usize>(minust) + 96, changetype<usize>(t.xy2d))
-
- fe_memcmov(changetype<usize>(t.yplusx), changetype<usize>(minust), bnegative)
- fe_memcmov(changetype<usize>(t.yminusx), changetype<usize>(minust) + 48, bnegative)
- fe_memcmov(changetype<usize>(t.xy2d), changetype<usize>(minust) + 96, bnegative)
-
- minust.fill(0)
+ // -(x, y) == (-x, y); for -x, y+x <-> y-x and negate xy2d
+ const n = v128.splat<u64>(0 - u64(isbneg))
+ const tp = changetype<usize>(t.yplusx)
+ const tm = changetype<usize>(t.yminusx)
+ const td = changetype<usize>(t.xy2d)
+
+ // y+x = y-x if n, else y+x
+ v128.store(tp, v128.bitselect(m0, p0, n))
+ v128.store(tp, v128.bitselect(m1, p1, n), 16)
+ v128.store_lane<u64>(tp, v128.bitselect(m2, p2, n), 0, 32)
+
+ // y-x = y+x if n, else y-x
+ v128.store(tm, v128.bitselect(p0, m0, n))
+ v128.store(tm, v128.bitselect(p1, m1, n), 16)
+ v128.store_lane<u64>(tm, v128.bitselect(p2, m2, n), 0, 32)
+
+ // xy2d = -xy2d if n, else xy2d
+ v128.store(td, v128.bitselect(v128.neg<i32>(d0), d0, n))
+ v128.store(td, v128.bitselect(v128.neg<i32>(d1), d1, n), 16)
+ v128.store_lane<u64>(td, v128.bitselect(v128.neg<i32>(d2), d2, n), 0, 32)
}
const u: FieldElement = fe()