* AssemblyScript compiler and type checker.
*/
+import { fe_add, fe_sub } from './fe.gen.mjs'
+
export const P = `//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
//@ts-expect-error
@inline
export function ge_p2_dbl (r: ge_p1p1, p: ge_p2): void {
- const t0 = ge_p2_dbl_t0
- fe_sq_vec(r.X, p.X, r.Z, p.Y)
- fe_sq2(r.T, p.Z)
- fe_add(r.Y, p.X, p.Y)
- fe_sq(t0, r.Y)
- fe_add(r.Y, r.Z, r.X)
- fe_sub(r.Z, r.Z, r.X)
- fe_sub(r.X, t0, r.Y)
- fe_sub(r.T, r.T, r.Z)
+ const rX_ptr = changetype<usize>(r.X)
+ const rY_ptr = changetype<usize>(r.Y)
+ const rZ_ptr = changetype<usize>(r.Z)
+ const rT_ptr = changetype<usize>(r.T)
+
+ const pX_ptr = changetype<usize>(p.X)
+ const pY_ptr = changetype<usize>(p.Y)
+ const pZ_ptr = changetype<usize>(p.Z)
+
+ const rYsq = ge_p2_dbl_t0
+ const rYsq_ptr = changetype<usize>(rYsq)
+
+ fe_sq_vec(r.X, r.Z, p.X, p.Y) // rX = pX²; rY = pY²
+ fe_sq2(r.T, p.Z) // rT = pZ²
+
+ // Start converting to performant inlined ops with locals to avoid load/store
+ let rX0 = v128.load(rX_ptr), rX1 = v128.load(rX_ptr, 16), rX2 = v128.load(rX_ptr, 32)
+ let rY0 = v128.load(rY_ptr), rY1 = v128.load(rY_ptr, 16), rY2 = v128.load(rY_ptr, 32)
+ let rZ0 = v128.load(rZ_ptr), rZ1 = v128.load(rZ_ptr, 16), rZ2 = v128.load(rZ_ptr, 32)
+ let rT0 = v128.load(rT_ptr), rT1 = v128.load(rT_ptr, 16), rT2 = v128.load(rT_ptr, 32)
+
+ const pX0 = v128.load(pX_ptr), pX1 = v128.load(pX_ptr, 16), pX2 = v128.load(pX_ptr, 32)
+ const pY0 = v128.load(pY_ptr), pY1 = v128.load(pY_ptr, 16), pY2 = v128.load(pY_ptr, 32)
+ const pZ0 = v128.load(pZ_ptr), pZ1 = v128.load(pZ_ptr, 16), pZ2 = v128.load(pZ_ptr, 32)
+
+ // rY = pX + pY
+ v128.store(rY_ptr, v128.add<i32>(pX0, pY0))
+ v128.store(rY_ptr, v128.add<i32>(pX1, pY1), 16)
+ v128.store_lane<u64>(rY_ptr, v128.add<i32>(pX2, pY2), 0, 32)
+
+ // t0 = r.Y²
+ fe_sq(rYsq, r.Y)
+ const rYsq0 = v128.load(rYsq_ptr, 0)
+ const rYsq1 = v128.load(rYsq_ptr, 16)
+ const rYsq2 = v128.load(rYsq_ptr, 32)
+
+ ${fe_add('rY', 'rZ', 'rX')}
+ ${fe_sub('rZ', 'rZ', 'rX')}
+ ${fe_sub('rX', 'rYsq', 'rY')}
+ ${fe_sub('rT', 'rT', 'rZ')}
+
+ // store r.X
+ v128.store(rX_ptr, rX0)
+ v128.store(rX_ptr, rX1, 16)
+ v128.store_lane<u64>(rX_ptr, rX2, 0, 32)
+
+ // store r.Y
+ v128.store(rY_ptr, rY0)
+ v128.store(rY_ptr, rY1, 16)
+ v128.store_lane<u64>(rY_ptr, rY2, 0, 32)
+
+ // store r.Z
+ v128.store(rZ_ptr, rZ0)
+ v128.store(rZ_ptr, rZ1, 16)
+ v128.store_lane<u64>(rZ_ptr, rZ2, 0, 32)
+
+ // store r.T
+ v128.store(rT_ptr, rT0)
+ v128.store(rT_ptr, rT1, 16)
+ v128.store_lane<u64>(rT_ptr, rT2, 0, 32)
}
/**
fe_0(h.xy2d)
}
-const ge_add_cached_t0: FieldElement = fe()
/**
* r = p + q
*/
export function ge_add_cached (r: ge_p1p1, p: ge_p3, q: ge_cached): void {
- const t0 = ge_add_cached_t0
- fe_add(r.X, p.Y, p.X)
- fe_sub(r.Y, p.Y, p.X)
+ const rX_ptr = changetype<usize>(r.X)
+ const rY_ptr = changetype<usize>(r.Y)
+ const rZ_ptr = changetype<usize>(r.Z)
+ const rT_ptr = changetype<usize>(r.T)
+
+ const pX_ptr = changetype<usize>(p.X)
+ const pY_ptr = changetype<usize>(p.Y)
+
+ let pX0 = v128.load(pX_ptr), pX1 = v128.load(pX_ptr, 16), pX2 = v128.load(pX_ptr, 32)
+ let pY0 = v128.load(pY_ptr), pY1 = v128.load(pY_ptr, 16), pY2 = v128.load(pY_ptr, 32)
+
+ // fe_add(r.X, p.Y, p.X)
+ let rX0 = v128.add<i32>(pY0, pX0)
+ let rX1 = v128.add<i32>(pY1, pX1)
+ let rX2 = v128.add<i32>(pY2, pX2)
+
+ // fe_sub(r.Y, p.Y, p.X)
+ let rY0 = v128.sub<i32>(pY0, pX0)
+ let rY1 = v128.sub<i32>(pY1, pX1)
+ let rY2 = v128.sub<i32>(pY2, pX2)
+
+ // store r.X
+ v128.store(rX_ptr, rX0)
+ v128.store(rX_ptr, rX1, 16)
+ v128.store_lane<u64>(rX_ptr, rX2, 0, 32)
+
+ // store r.Y
+ v128.store(rY_ptr, rY0)
+ v128.store(rY_ptr, rY1, 16)
+ v128.store_lane<u64>(rY_ptr, rY2, 0, 32)
+
+ // not yet converted to inline for size and complexity
fe_mul(r.Z, r.X, q.YplusX)
fe_mul(r.Y, r.Y, q.YminusX)
fe_mul(r.T, q.T2d, p.T)
fe_mul(r.X, p.Z, q.Z)
- fe_dbl(t0, r.X)
- fe_sub(r.X, r.Z, r.Y)
- fe_add(r.Y, r.Z, r.Y)
- fe_add(r.Z, t0, r.T)
- fe_sub(r.T, t0, r.T)
+
+ // remaining arithmetic done inline to avoid unnecessary load/store
+ rX0 = v128.load(rX_ptr), rX1 = v128.load(rX_ptr, 16), rX2 = v128.load(rX_ptr, 32)
+ rY0 = v128.load(rY_ptr), rY1 = v128.load(rY_ptr, 16), rY2 = v128.load(rY_ptr, 32)
+ let rZ0 = v128.load(rZ_ptr), rZ1 = v128.load(rZ_ptr, 16), rZ2 = v128.load(rZ_ptr, 32)
+ let rT0 = v128.load(rT_ptr), rT1 = v128.load(rT_ptr, 16), rT2 = v128.load(rT_ptr, 32)
+
+ // fe_dbl(t0, r.X)
+ const t0 = v128.shl<i32>(rX0, 1)
+ const t1 = v128.shl<i32>(rX1, 1)
+ const t2 = v128.shl<i32>(rX2, 1)
+
+ // fe_sub(r.X, r.Z, r.Y)
+ rX0 = v128.sub<i32>(rZ0, rY0)
+ rX1 = v128.sub<i32>(rZ1, rY1)
+ rX2 = v128.sub<i32>(rZ2, rY2)
+
+ // fe_add(r.Y, r.Z, r.Y)
+ rY0 = v128.add<i32>(rZ0, rY0)
+ rY1 = v128.add<i32>(rZ1, rY1)
+ rY2 = v128.add<i32>(rZ2, rY2)
+
+ // fe_add(r.Z, t, r.T)
+ rZ0 = v128.add<i32>(t0, rT0)
+ rZ1 = v128.add<i32>(t1, rT1)
+ rZ2 = v128.add<i32>(t2, rT2)
+
+ // fe_sub(r.T, t, r.T)
+ rT0 = v128.sub<i32>(t0, rT0)
+ rT1 = v128.sub<i32>(t1, rT1)
+ rT2 = v128.sub<i32>(t2, rT2)
+
+ // store r.X
+ v128.store(rX_ptr, rX0)
+ v128.store(rX_ptr, rX1, 16)
+ v128.store_lane<u64>(rX_ptr, rX2, 0, 32)
+
+ // store r.Y
+ v128.store(rY_ptr, rY0)
+ v128.store(rY_ptr, rY1, 16)
+ v128.store_lane<u64>(rY_ptr, rY2, 0, 32)
+
+ // store r.Z
+ v128.store(rZ_ptr, rZ0)
+ v128.store(rZ_ptr, rZ1, 16)
+ v128.store_lane<u64>(rZ_ptr, rZ2, 0, 32)
+
+ // store r.T
+ v128.store(rT_ptr, rT0)
+ v128.store(rT_ptr, rT1, 16)
+ v128.store_lane<u64>(rT_ptr, rT2, 0, 32)
}
-const ge_add_precomp_t0: FieldElement = fe()
/**
* r = p + q
*/
//@ts-expect-error
@inline
export function ge_add_precomp (r: ge_p1p1, p: ge_p3, q: ge_precomp): void {
- const t0 = ge_add_precomp_t0
- fe_add(r.X, p.Y, p.X)
- fe_sub(r.Y, p.Y, p.X)
+ const rX_ptr = changetype<usize>(r.X)
+ const rY_ptr = changetype<usize>(r.Y)
+ const rZ_ptr = changetype<usize>(r.Z)
+ const rT_ptr = changetype<usize>(r.T)
+
+ const pX_ptr = changetype<usize>(p.X)
+ const pY_ptr = changetype<usize>(p.Y)
+ const pZ_ptr = changetype<usize>(p.Z)
+
+ const pX0 = v128.load(pX_ptr), pX1 = v128.load(pX_ptr, 16), pX2 = v128.load(pX_ptr, 32)
+ const pY0 = v128.load(pY_ptr), pY1 = v128.load(pY_ptr, 16), pY2 = v128.load(pY_ptr, 32)
+
+ // fe_add(r.X, p.Y, p.X)
+ let rX0 = v128.add<i32>(pY0, pX0)
+ let rX1 = v128.add<i32>(pY1, pX1)
+ let rX2 = v128.add<i32>(pY2, pX2)
+
+ // fe_sub(r.Y, p.Y, p.X)
+ let rY0 = v128.sub<i32>(pY0, pX0)
+ let rY1 = v128.sub<i32>(pY1, pX1)
+ let rY2 = v128.sub<i32>(pY2, pX2)
+
+ // store r.X
+ v128.store(rX_ptr, rX0)
+ v128.store(rX_ptr, rX1, 16)
+ v128.store_lane<u64>(rX_ptr, rX2, 0, 32)
+
+ // store r.Y
+ v128.store(rY_ptr, rY0)
+ v128.store(rY_ptr, rY1, 16)
+ v128.store_lane<u64>(rY_ptr, rY2, 0, 32)
+
+ // not yet converted to inline for size and complexity
fe_mul(r.Z, r.X, q.yplusx)
fe_mul(r.Y, r.Y, q.yminusx)
fe_mul(r.T, q.xy2d, p.T)
- fe_dbl(t0, p.Z)
- fe_sub(r.X, r.Z, r.Y)
- fe_add(r.Y, r.Z, r.Y)
- fe_add(r.Z, t0, r.T)
- fe_sub(r.T, t0, r.T)
+
+ // remaining arithmetic done inline to avoid unnecessary load/store
+ rX0 = v128.load(rX_ptr), rX1 = v128.load(rX_ptr, 16), rX2 = v128.load(rX_ptr, 32)
+ rY0 = v128.load(rY_ptr), rY1 = v128.load(rY_ptr, 16), rY2 = v128.load(rY_ptr, 32)
+ let rZ0 = v128.load(rZ_ptr), rZ1 = v128.load(rZ_ptr, 16), rZ2 = v128.load(rZ_ptr, 32)
+ let rT0 = v128.load(rT_ptr), rT1 = v128.load(rT_ptr, 16), rT2 = v128.load(rT_ptr, 32)
+
+ // fe_dbl(t, p.Z)
+ const pZ0 = v128.shl<i32>(v128.load(pZ_ptr), 1)
+ const pZ1 = v128.shl<i32>(v128.load(pZ_ptr, 16), 1)
+ const pZ2 = v128.shl<i32>(v128.load(pZ_ptr, 32), 1)
+
+ // fe_sub(r.X, r.Z, r.Y)
+ rX0 = v128.sub<i32>(rZ0, rY0)
+ rX1 = v128.sub<i32>(rZ1, rY1)
+ rX2 = v128.sub<i32>(rZ2, rY2)
+
+ // fe_add(r.Y, r.Z, r.Y)
+ rY0 = v128.add<i32>(rZ0, rY0)
+ rY1 = v128.add<i32>(rZ1, rY1)
+ rY2 = v128.add<i32>(rZ2, rY2)
+
+ // fe_add(r.Z, t, r.T)
+ rZ0 = v128.add<i32>(pZ0, rT0)
+ rZ1 = v128.add<i32>(pZ1, rT1)
+ rZ2 = v128.add<i32>(pZ2, rT2)
+
+ // fe_sub(r.T, t, r.T)
+ rT0 = v128.sub<i32>(pZ0, rT0)
+ rT1 = v128.sub<i32>(pZ1, rT1)
+ rT2 = v128.sub<i32>(pZ2, rT2)
+
+ // store r.X
+ v128.store(rX_ptr, rX0)
+ v128.store(rX_ptr, rX1, 16)
+ v128.store_lane<u64>(rX_ptr, rX2, 0, 32)
+
+ // store r.Y
+ v128.store(rY_ptr, rY0)
+ v128.store(rY_ptr, rY1, 16)
+ v128.store_lane<u64>(rY_ptr, rY2, 0, 32)
+
+ // store r.Z
+ v128.store(rZ_ptr, rZ0)
+ v128.store(rZ_ptr, rZ1, 16)
+ v128.store_lane<u64>(rZ_ptr, rZ2, 0, 32)
+
+ // store r.T
+ v128.store(rT_ptr, rT0)
+ v128.store(rT_ptr, rT1, 16)
+ v128.store_lane<u64>(rT_ptr, rT2, 0, 32)
}
const ge_sub_p3_q_cached = new ge_cached()