<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />

SidhCompressed

sealed class SidhCompressed
using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Pqc.Crypto.Sike { internal sealed class SidhCompressed { private readonly SikeEngine engine; private static uint t_points = 2; internal SidhCompressed(SikeEngine engine) { this.engine = engine; } internal void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR) { engine.fpx.fpcopy(gen, 0, XP[0]); engine.fpx.fpcopy(gen, engine.param.NWORDS_FIELD, XP[1]); engine.fpx.fpcopy(gen, 2 * engine.param.NWORDS_FIELD, XQ[0]); engine.fpx.fpcopy(gen, 3 * engine.param.NWORDS_FIELD, XQ[1]); engine.fpx.fpcopy(gen, 4 * engine.param.NWORDS_FIELD, XR[0]); engine.fpx.fpcopy(gen, 5 * engine.param.NWORDS_FIELD, XR[1]); } internal void FormatPrivKey_B(byte[] skB) { skB[engine.param.SECRETKEY_B_BYTES - 2] &= (byte)engine.param.MASK3_BOB; skB[engine.param.SECRETKEY_B_BYTES - 1] &= (byte)engine.param.MASK2_BOB; engine.fpx.mul3(skB); } internal void random_mod_order_A(byte[] random_digits, SecureRandom random) { byte[] array = new byte[engine.param.SECRETKEY_A_BYTES]; random.NextBytes(array); Array.Copy(array, 0, random_digits, 0, engine.param.SECRETKEY_A_BYTES); random_digits[0] &= 254; random_digits[engine.param.SECRETKEY_A_BYTES - 1] &= (byte)engine.param.MASK_ALICE; } internal void random_mod_order_B(byte[] random_digits, SecureRandom random) { byte[] array = new byte[engine.param.SECRETKEY_B_BYTES]; random.NextBytes(array); Array.Copy(array, 0, random_digits, 0, engine.param.SECRETKEY_A_BYTES); FormatPrivKey_B(random_digits); } internal void Ladder3pt_dual(PointProj[] Rs, ulong[] m, uint AliceOrBob, PointProj R, ulong[][] A24) { PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); uint num = 0; uint num2 = (AliceOrBob != engine.param.ALICE) ? engine.param.OBOB_BITS : engine.param.OALICE_BITS; engine.fpx.fp2copy(Rs[1].X, pointProj.X); engine.fpx.fp2copy(Rs[1].Z, pointProj.Z); engine.fpx.fp2copy(Rs[2].X, pointProj2.X); engine.fpx.fp2copy(Rs[2].Z, pointProj2.Z); engine.fpx.fp2copy(Rs[0].X, R.X); engine.fpx.fp2copy(Rs[0].Z, R.Z); uint num5; ulong option; for (uint num3 = 0; num3 < num2; num3++) { int num4 = (int)((m[num3 >> (int)Internal.LOG2RADIX] >> (int)(num3 & (Internal.RADIX - 1))) & 1); num5 = (uint)(num4 ^ (int)num); num = (uint)num4; option = (ulong)(0 - (long)num5); engine.isogeny.SwapPoints(R, pointProj2, option); engine.isogeny.XDblAdd(pointProj, pointProj2, R.X, A24); engine.fpx.fp2mul_mont(pointProj2.X, R.Z, pointProj2.X); } num5 = (0 ^ num); option = (ulong)(0 - (long)num5); engine.isogeny.SwapPoints(R, pointProj2, option); } internal void Elligator2(ulong[][] a24, uint[] r, uint rIndex, ulong[][] x, byte[] bit, uint bitOffset, uint COMPorDEC) { ulong[] array = new ulong[engine.param.NWORDS_FIELD]; ulong[] array2 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array3 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array4 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array5 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array6 = new ulong[engine.param.NWORDS_FIELD]; ulong[][] array7 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array8 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); uint num = 0; engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array); engine.fpx.fp2add(a24, a24, array7); engine.fpx.fpsubPRIME(array7[0], array, array7[0]); engine.fpx.fp2add(array7, array7, array7); num = r[rIndex]; engine.fpx.fp2mul_mont(array7, engine.param.v_3_torsion[num], x); engine.fpx.fp2neg(x); if (COMPorDEC == 0) { engine.fpx.fp2add(array7, x, array8); engine.fpx.fp2mul_mont(array8, x, array8); engine.fpx.fpaddPRIME(array8[0], array, array8[0]); engine.fpx.fp2mul_mont(x, array8, array8); engine.fpx.fpsqr_mont(array8[0], array2); engine.fpx.fpsqr_mont(array8[1], array3); engine.fpx.fpaddPRIME(array2, array3, array4); engine.fpx.fpcopy(array4, 0, array5); for (uint num2 = 0; num2 < engine.param.OALICE_BITS - 2; num2++) { engine.fpx.fpsqr_mont(array5, array5); } for (uint num2 = 0; num2 < engine.param.OBOB_EXPON; num2++) { engine.fpx.fpsqr_mont(array5, array6); engine.fpx.fpmul_mont(array5, array6, array5); } engine.fpx.fpsqr_mont(array5, array6); engine.fpx.fpcorrectionPRIME(array6); engine.fpx.fpcorrectionPRIME(array4); if (!Fpx.subarrayEquals(array6, array4, engine.param.NWORDS_FIELD)) { engine.fpx.fp2neg(x); engine.fpx.fp2sub(x, array7, x); if (COMPorDEC == 0) bit[bitOffset] = 1; } } else if (bit[bitOffset] == 1) { engine.fpx.fp2neg(x); engine.fpx.fp2sub(x, array7, x); } } internal void make_positive(ulong[][] x) { uint nWORDS_FIELD = engine.param.NWORDS_FIELD; ulong[] b = new ulong[engine.param.NWORDS_FIELD]; engine.fpx.from_fp2mont(x, x); if (!Fpx.subarrayEquals(x[0], b, nWORDS_FIELD)) { if ((x[0][0] & 1) == 1) engine.fpx.fp2neg(x); } else if ((x[1][0] & 1) == 1) { engine.fpx.fp2neg(x); } engine.fpx.to_fp2mont(x, x); } internal void BiQuad_affine(ulong[][] a24, ulong[][] x0, ulong[][] x1, PointProj R) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2add(a24, a24, array); engine.fpx.fp2add(array, array, array); engine.fpx.fp2sub(x0, x1, array2); engine.fpx.fp2sqr_mont(array2, array2); engine.fpx.fp2mul_mont(x0, x1, array4); engine.fpx.fpsubPRIME(array4[0], engine.param.Montgomery_one, array4[0]); engine.fpx.fp2sqr_mont(array4, array4); engine.fpx.fpsubPRIME(x0[0], engine.param.Montgomery_one, array3[0]); engine.fpx.fpcopy(x0[1], 0, array3[1]); engine.fpx.fp2sqr_mont(array3, array3); engine.fpx.fp2mul_mont(array, x0, array5); engine.fpx.fp2add(array3, array5, array3); engine.fpx.fp2mul_mont(x1, array3, array3); engine.fpx.fpsubPRIME(x1[0], engine.param.Montgomery_one, array5[0]); engine.fpx.fpcopy(x1[1], 0, array5[1]); engine.fpx.fp2sqr_mont(array5, array5); engine.fpx.fp2mul_mont(array, x1, array6); engine.fpx.fp2add(array5, array6, array5); engine.fpx.fp2mul_mont(x0, array5, array5); engine.fpx.fp2add(array3, array5, array3); engine.fpx.fp2add(array3, array3, array3); engine.fpx.fp2sqr_mont(array3, array5); engine.fpx.fp2mul_mont(array2, array4, array6); engine.fpx.fp2add(array6, array6, array6); engine.fpx.fp2add(array6, array6, array6); engine.fpx.fp2sub(array5, array6, array5); engine.fpx.sqrt_Fp2(array5, array5); make_positive(array5); engine.fpx.fp2add(array3, array5, R.X); engine.fpx.fp2add(array2, array2, R.Z); } internal void get_4_isog_dual(PointProj P, ulong[][] A24, ulong[][] C24, ulong[][][] coeff) { engine.fpx.fp2sub(P.X, P.Z, coeff[1]); engine.fpx.fp2add(P.X, P.Z, coeff[2]); engine.fpx.fp2sqr_mont(P.Z, coeff[4]); engine.fpx.fp2add(coeff[4], coeff[4], coeff[0]); engine.fpx.fp2sqr_mont(coeff[0], C24); engine.fpx.fp2add(coeff[0], coeff[0], coeff[0]); engine.fpx.fp2sqr_mont(P.X, coeff[3]); engine.fpx.fp2add(coeff[3], coeff[3], A24); engine.fpx.fp2sqr_mont(A24, A24); } internal void eval_dual_2_isog(ulong[][] X2, ulong[][] Z2, PointProj P) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2add(P.X, P.Z, array); engine.fpx.fp2sub(P.X, P.Z, P.Z); engine.fpx.fp2sqr_mont(array, array); engine.fpx.fp2sqr_mont(P.Z, P.Z); engine.fpx.fp2sub(array, P.Z, P.Z); engine.fpx.fp2mul_mont(X2, P.Z, P.Z); engine.fpx.fp2mul_mont(Z2, array, P.X); } internal void eval_final_dual_2_isog(PointProj P) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[] array3 = new ulong[engine.param.NWORDS_FIELD]; engine.fpx.fp2add(P.X, P.Z, array); engine.fpx.fp2mul_mont(P.X, P.Z, array2); engine.fpx.fp2sqr_mont(array, P.X); engine.fpx.fpcopy(P.X[0], 0, array3); engine.fpx.fpcopy(P.X[1], 0, P.X[0]); engine.fpx.fpcopy(array3, 0, P.X[1]); engine.fpx.fpnegPRIME(P.X[1]); engine.fpx.fp2add(array2, array2, P.Z); engine.fpx.fp2add(P.Z, P.Z, P.Z); } internal void eval_dual_4_isog_shared(ulong[][] X4pZ4, ulong[][] X42, ulong[][] Z42, ulong[][][] coeff, uint coeffOffset) { engine.fpx.fp2sub(X42, Z42, coeff[coeffOffset]); engine.fpx.fp2add(X42, Z42, coeff[1 + coeffOffset]); engine.fpx.fp2sqr_mont(X4pZ4, coeff[2 + coeffOffset]); engine.fpx.fp2sub(coeff[2 + coeffOffset], coeff[1 + coeffOffset], coeff[2 + coeffOffset]); } internal void eval_dual_4_isog(ulong[][] A24, ulong[][] C24, ulong[][][] coeff, uint coeffOffset, PointProj P) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2add(P.X, P.Z, array); engine.fpx.fp2sub(P.X, P.Z, array2); engine.fpx.fp2sqr_mont(array, array); engine.fpx.fp2sqr_mont(array2, array2); engine.fpx.fp2sub(array, array2, array3); engine.fpx.fp2sub(C24, A24, array4); engine.fpx.fp2mul_mont(array3, array4, array4); engine.fpx.fp2mul_mont(C24, array, array3); engine.fpx.fp2sub(array3, array4, array3); engine.fpx.fp2mul_mont(array3, array, P.X); engine.fpx.fp2mul_mont(array4, array2, P.Z); engine.fpx.fp2mul_mont(coeff[coeffOffset], P.X, P.X); engine.fpx.fp2mul_mont(coeff[1 + coeffOffset], P.Z, array); engine.fpx.fp2add(P.X, array, P.X); engine.fpx.fp2mul_mont(coeff[2 + coeffOffset], P.Z, P.Z); } internal void eval_full_dual_4_isog(ulong[][][][] As, PointProj P) { for (uint num = 0; num < engine.param.MAX_Alice; num++) { eval_dual_4_isog(As[engine.param.MAX_Alice - num][0], As[engine.param.MAX_Alice - num][1], As[engine.param.MAX_Alice - num - 1], 2, P); } if (engine.param.OALICE_BITS % 2 == 1) eval_dual_2_isog(As[engine.param.MAX_Alice][2], As[engine.param.MAX_Alice][3], P); eval_final_dual_2_isog(P); } internal void TripleAndParabola_proj(PointProjFull R, ulong[][] l1x, ulong[][] l1z) { engine.fpx.fp2sqr_mont(R.X, l1z); engine.fpx.fp2add(l1z, l1z, l1x); engine.fpx.fp2add(l1x, l1z, l1x); engine.fpx.fpaddPRIME(l1x[0], engine.param.Montgomery_one, l1x[0]); engine.fpx.fp2add(R.Y, R.Y, l1z); } internal void Tate3_proj(PointProjFull P, PointProjFull Q, ulong[][] gX, ulong[][] gZ) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); TripleAndParabola_proj(P, array2, gZ); engine.fpx.fp2sub(Q.X, P.X, gX); engine.fpx.fp2mul_mont(array2, gX, gX); engine.fpx.fp2sub(P.Y, Q.Y, array); engine.fpx.fp2mul_mont(gZ, array, array); engine.fpx.fp2add(gX, array, gX); } internal void FinalExpo3(ulong[][] gX, ulong[][] gZ) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2copy(gZ, array); engine.fpx.fpnegPRIME(array[1]); engine.fpx.fp2mul_mont(gX, array, array); engine.fpx.fp2inv_mont_bingcd(array); engine.fpx.fpnegPRIME(gX[1]); engine.fpx.fp2mul_mont(gX, gZ, gX); engine.fpx.fp2mul_mont(gX, array, gX); for (uint num = 0; num < engine.param.OALICE_BITS; num++) { engine.fpx.fp2sqr_mont(gX, gX); } for (uint num = 0; num < engine.param.OBOB_EXPON - 1; num++) { engine.fpx.cube_Fp2_cycl(gX, engine.param.Montgomery_one); } } internal void FinalExpo3_2way(ulong[][][] gX, ulong[][][] gZ) { ulong[][][] array = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD); ulong[][][] array2 = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD); for (uint num = 0; num < 2; num++) { engine.fpx.fp2copy(gZ[num], array[num]); engine.fpx.fpnegPRIME(array[num][1]); engine.fpx.fp2mul_mont(gX[num], array[num], array[num]); } engine.fpx.mont_n_way_inv(array, 2, array2); for (uint num = 0; num < 2; num++) { engine.fpx.fpnegPRIME(gX[num][1]); engine.fpx.fp2mul_mont(gX[num], gZ[num], gX[num]); engine.fpx.fp2mul_mont(gX[num], array2[num], gX[num]); for (uint num2 = 0; num2 < engine.param.OALICE_BITS; num2++) { engine.fpx.fp2sqr_mont(gX[num], gX[num]); } for (uint num2 = 0; num2 < engine.param.OBOB_EXPON - 1; num2++) { engine.fpx.cube_Fp2_cycl(gX[num], engine.param.Montgomery_one); } } } private bool FirstPoint_dual(PointProj P, PointProjFull R, byte[] ind) { PointProjFull pointProjFull = new PointProjFull(engine.param.NWORDS_FIELD); PointProjFull pointProjFull2 = new PointProjFull(engine.param.NWORDS_FIELD); ulong[][][] array = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD); ulong[][][] array2 = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD); ulong[] b = new ulong[engine.param.NWORDS_FIELD]; uint nWORDS_FIELD = engine.param.NWORDS_FIELD; Fpx fpx = engine.fpx; ulong[] b_gen_3_tors = engine.param.B_gen_3_tors; uint nWORDS_FIELD2 = engine.param.NWORDS_FIELD; fpx.fpcopy(b_gen_3_tors, 0, pointProjFull.X[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, engine.param.NWORDS_FIELD, pointProjFull.X[1]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 2 * engine.param.NWORDS_FIELD, pointProjFull.Y[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 3 * engine.param.NWORDS_FIELD, pointProjFull.Y[1]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 4 * engine.param.NWORDS_FIELD, pointProjFull2.X[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 5 * engine.param.NWORDS_FIELD, pointProjFull2.X[1]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 6 * engine.param.NWORDS_FIELD, pointProjFull2.Y[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, 7 * engine.param.NWORDS_FIELD, pointProjFull2.Y[1]); engine.isogeny.CompletePoint(P, R); Tate3_proj(pointProjFull, R, array[0], array2[0]); Tate3_proj(pointProjFull2, R, array[1], array2[1]); FinalExpo3_2way(array, array2); engine.fpx.fp2correction(array[0]); engine.fpx.fp2correction(array[1]); uint num = (uint)((!Fpx.subarrayEquals(array[0][1], b, nWORDS_FIELD)) ? (Fpx.subarrayEquals(array[0][1], engine.param.g_R_S_im, nWORDS_FIELD) ? 1 : 2) : 0); uint num2 = (uint)((!Fpx.subarrayEquals(array[1][1], b, nWORDS_FIELD)) ? (Fpx.subarrayEquals(array[1][1], engine.param.g_R_S_im, nWORDS_FIELD) ? 1 : 2) : 0); if (num == 0 && num2 == 0) return false; if (num == 0) ind[0] = 0; else if (num2 == 0) { ind[0] = 1; } else if (num + num2 == 3) { ind[0] = 3; } else { ind[0] = 2; } return true; } private bool SecondPoint_dual(PointProj P, PointProjFull R, byte[] ind) { PointProjFull pointProjFull = new PointProjFull(engine.param.NWORDS_FIELD); ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] gZ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[] b = new ulong[engine.param.NWORDS_FIELD]; uint nWORDS_FIELD = engine.param.NWORDS_FIELD; engine.fpx.fpcopy(engine.param.B_gen_3_tors, 4 * ind[0] * engine.param.NWORDS_FIELD, pointProjFull.X[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, (4 * ind[0] + 1) * engine.param.NWORDS_FIELD, pointProjFull.X[1]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, (4 * ind[0] + 2) * engine.param.NWORDS_FIELD, pointProjFull.Y[0]); engine.fpx.fpcopy(engine.param.B_gen_3_tors, (4 * ind[0] + 3) * engine.param.NWORDS_FIELD, pointProjFull.Y[1]); engine.isogeny.CompletePoint(P, R); Tate3_proj(pointProjFull, R, array, gZ); FinalExpo3(array, gZ); engine.fpx.fp2correction(array); if (!Fpx.subarrayEquals(array[1], b, nWORDS_FIELD)) return true; return false; } internal void FirstPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) { bool flag = false; PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); ulong[] a25 = new ulong[engine.param.NWORDS_FIELD]; r[0] = 0; while (!flag) { bitEll[0] = 0; Elligator2(a24, r, 0, x, bitEll, 0, 0); engine.fpx.fp2copy(x, pointProj.X); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, pointProj.Z[0]); engine.fpx.fpcopy(a25, 0, pointProj.Z[1]); eval_full_dual_4_isog(As, pointProj); flag = FirstPoint_dual(pointProj, R, ind); r[0] = r[0] + 1; } } internal void SecondPoint3n(ulong[][] a24, ulong[][][][] As, ulong[][] x, PointProjFull R, uint[] r, byte[] ind, byte[] bitEll) { bool flag = false; PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); ulong[] a25 = new ulong[engine.param.NWORDS_FIELD]; while (!flag) { bitEll[0] = 0; Elligator2(a24, r, 1, x, bitEll, 0, 0); engine.fpx.fp2copy(x, pointProj.X); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, pointProj.Z[0]); engine.fpx.fpcopy(a25, 0, pointProj.Z[1]); eval_full_dual_4_isog(As, pointProj); flag = SecondPoint_dual(pointProj, R, ind); r[1] = r[1] + 1; } } internal void makeDiff(PointProjFull R, PointProjFull S, PointProj D) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); uint nWORDS_FIELD = engine.param.NWORDS_FIELD; engine.fpx.fp2sub(R.X, S.X, array); engine.fpx.fp2sub(R.Y, S.Y, array2); engine.fpx.fp2sqr_mont(array, array); engine.fpx.fp2sqr_mont(array2, array2); engine.fpx.fp2add(R.X, S.X, array3); engine.fpx.fp2mul_mont(array, array3, array3); engine.fpx.fp2sub(array2, array3, array2); engine.fpx.fp2mul_mont(D.Z, array2, array2); engine.fpx.fp2mul_mont(D.X, array, array); engine.fpx.fp2correction(array); engine.fpx.fp2correction(array2); if (Fpx.subarrayEquals(array[0], array2[0], nWORDS_FIELD) & Fpx.subarrayEquals(array[1], array2[1], nWORDS_FIELD)) engine.fpx.fp2neg(S.Y); } internal void BuildOrdinary3nBasis_dual(ulong[][] a24, ulong[][][][] As, PointProjFull[] R, uint[] r, uint[] bitsEll, uint bitsEllOffset) { PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); ulong[][][] array = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD); byte[] ind = new byte[1]; byte[] array2 = new byte[1]; FirstPoint3n(a24, As, array[0], R[0], r, ind, array2); bitsEll[bitsEllOffset] = array2[0]; r[1] = r[0]; SecondPoint3n(a24, As, array[1], R[1], r, ind, array2); bitsEll[bitsEllOffset] |= (uint)(array2[0] << 1); BiQuad_affine(a24, array[0], array[1], pointProj); eval_full_dual_4_isog(As, pointProj); makeDiff(R[0], R[1], pointProj); } internal void FullIsogeny_A_dual(byte[] PrivateKeyA, ulong[][][][] As, ulong[][] a24, uint sike) { PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj[] array = new PointProj[engine.param.MAX_INT_POINTS_ALICE]; ulong[][] xP = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] xQ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] array6 = SikeUtilities.InitArray(5, 2, engine.param.NWORDS_FIELD); uint num = 0; uint num2 = 0; uint num3 = 0; uint[] array7 = new uint[engine.param.MAX_INT_POINTS_ALICE]; ulong[] array8 = new ulong[engine.param.NWORDS_ORDER]; init_basis(engine.param.A_gen, xP, xQ, array2); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[0]); engine.fpx.fp2add(array3, array3, array3); engine.fpx.fp2add(array3, array3, array4); engine.fpx.fp2add(array3, array4, array5); engine.fpx.fp2add(array4, array4, array3); engine.fpx.decode_to_digits(PrivateKeyA, engine.param.MSG_BYTES, array8, engine.param.SECRETKEY_A_BYTES, engine.param.NWORDS_ORDER); engine.isogeny.LADDER3PT(xP, xQ, array2, array8, engine.param.ALICE, pointProj, array5); engine.fpx.fp2inv_mont(pointProj.Z); engine.fpx.fp2mul_mont(pointProj.X, pointProj.Z, pointProj.X); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, pointProj.Z[0]); engine.fpx.fpzero(pointProj.Z[1]); if (sike == 1) engine.fpx.fp2_encode(pointProj.X, PrivateKeyA, engine.param.MSG_BYTES + engine.param.SECRETKEY_A_BYTES + engine.param.CRYPTO_PUBLICKEYBYTES); if (engine.param.OALICE_BITS % 2 == 1) { PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); engine.isogeny.XDblE(pointProj, pointProj2, array3, array4, engine.param.OALICE_BITS - 1); engine.isogeny.Get2Isog(pointProj2, array3, array4); engine.isogeny.Eval2Isog(pointProj, pointProj2); engine.fpx.fp2copy(pointProj2.X, As[engine.param.MAX_Alice][2]); engine.fpx.fp2copy(pointProj2.Z, As[engine.param.MAX_Alice][3]); } num = 0; for (uint num4 = 1; num4 < engine.param.MAX_Alice; num4++) { uint num7; for (; num < engine.param.MAX_Alice - num4; num += num7) { array[num2] = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.fp2copy(pointProj.X, array[num2].X); engine.fpx.fp2copy(pointProj.Z, array[num2].Z); array7[num2++] = num; num7 = engine.param.strat_Alice[num3++]; engine.isogeny.XDblE(pointProj, pointProj, array3, array4, 2 * num7); } engine.fpx.fp2copy(array3, As[num4 - 1][0]); engine.fpx.fp2copy(array4, As[num4 - 1][1]); get_4_isog_dual(pointProj, array3, array4, array6); for (uint num8 = 0; num8 < num2; num8++) { engine.isogeny.Eval4Isog(array[num8], array6); } eval_dual_4_isog_shared(array6[2], array6[3], array6[4], As[num4 - 1], 2); engine.fpx.fp2copy(array[num2 - 1].X, pointProj.X); engine.fpx.fp2copy(array[num2 - 1].Z, pointProj.Z); num = array7[num2 - 1]; num2--; } engine.fpx.fp2copy(array3, As[engine.param.MAX_Alice - 1][0]); engine.fpx.fp2copy(array4, As[engine.param.MAX_Alice - 1][1]); get_4_isog_dual(pointProj, array3, array4, array6); eval_dual_4_isog_shared(array6[2], array6[3], array6[4], As[engine.param.MAX_Alice - 1], 2); engine.fpx.fp2copy(array3, As[engine.param.MAX_Alice][0]); engine.fpx.fp2copy(array4, As[engine.param.MAX_Alice][1]); engine.fpx.fp2inv_mont_bingcd(array4); engine.fpx.fp2mul_mont(array3, array4, a24); } internal void Dlogs3_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) { solve_dlog(f[0], D, d0, 3); solve_dlog(f[2], D, c0, 3); solve_dlog(f[1], D, d1, 3); solve_dlog(f[3], D, c1, 3); engine.fpx.mp_sub(engine.param.Bob_order, c0, c0, engine.param.NWORDS_ORDER); engine.fpx.mp_sub(engine.param.Bob_order, c1, c1, engine.param.NWORDS_ORDER); } internal void BuildOrdinary3nBasis_Decomp_dual(ulong[][] A24, PointProj[] Rs, uint[] r, uint[] bitsEll, uint bitsEllIndex) { byte[] bit = new byte[2] { (byte)(bitsEll[bitsEllIndex] & 1), (byte)((bitsEll[bitsEllIndex] >> 1) & 1) }; r[0]--; Elligator2(A24, r, 0, Rs[0].X, bit, 0, 1); r[1]--; Elligator2(A24, r, 1, Rs[1].X, bit, 1, 1); BiQuad_affine(A24, Rs[0].X, Rs[1].X, Rs[2]); } internal void PKADecompression_dual(byte[] SecretKeyB, byte[] CompressedPKA, PointProj R, ulong[][] A) { uint[] array = new uint[3]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PointProj[] array3 = new PointProj[3] { new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD) }; ulong[] array4 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array5 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array6 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array7 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array8 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array9 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array10 = new ulong[engine.param.NWORDS_ORDER]; engine.fpx.fp2_decode(CompressedPKA, A, 3 * engine.param.ORDER_B_ENCODED_BYTES); array8[0] = 1; engine.fpx.to_Montgomery_mod_order(array8, array8, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); byte b = (byte)((CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] & 255) >> 7); byte[] array11 = new byte[3]; Array.Copy(CompressedPKA, 3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES, array11, 0, 3); array[0] = (uint)(array11[0] & 65535); array[1] = (uint)(array11[1] & 65535); array[2] = (uint)(array11[2] & 65535); array[0] &= 127; engine.fpx.fpaddPRIME(A[0], engine.param.Montgomery_one, array2[0]); engine.fpx.fpcopy(A[1], 0, array2[1]); engine.fpx.fpaddPRIME(array2[0], engine.param.Montgomery_one, array2[0]); engine.fpx.fp2div2(array2, array2); engine.fpx.fp2div2(array2, array2); BuildOrdinary3nBasis_Decomp_dual(array2, array3, array, array, 2); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[1].Z[0]); engine.isogeny.SwapPoints(array3[0], array3[1], (ulong)(-b)); engine.fpx.decode_to_digits(SecretKeyB, 0, array10, engine.param.SECRETKEY_B_BYTES, engine.param.NWORDS_ORDER); engine.fpx.to_Montgomery_mod_order(array10, array4, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.decode_to_digits(CompressedPKA, 0, array9, engine.param.ORDER_B_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.to_Montgomery_mod_order(array9, array5, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.decode_to_digits(CompressedPKA, engine.param.ORDER_B_ENCODED_BYTES, array9, engine.param.ORDER_B_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.to_Montgomery_mod_order(array9, array6, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.decode_to_digits(CompressedPKA, 2 * engine.param.ORDER_B_ENCODED_BYTES, array9, engine.param.ORDER_B_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.to_Montgomery_mod_order(array9, array7, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); if (b == 0) { engine.fpx.Montgomery_multiply_mod_order(array4, array6, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.mp_add(array6, array8, array6, engine.param.NWORDS_ORDER); engine.fpx.Montgomery_inversion_mod_order_bingcd(array6, array6, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.Montgomery_multiply_mod_order(array4, array7, array7, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.mp_add(array5, array7, array7, engine.param.NWORDS_ORDER); engine.fpx.Montgomery_multiply_mod_order(array6, array7, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array6, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); Ladder3pt_dual(array3, array6, engine.param.BOB, R, array2); } else { engine.fpx.Montgomery_multiply_mod_order(array4, array7, array7, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.mp_add(array7, array8, array7, engine.param.NWORDS_ORDER); engine.fpx.Montgomery_inversion_mod_order_bingcd(array7, array7, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.Montgomery_multiply_mod_order(array4, array6, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.mp_add(array5, array6, array6, engine.param.NWORDS_ORDER); engine.fpx.Montgomery_multiply_mod_order(array6, array7, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array6, array6, engine.param.Bob_order, engine.param.Montgomery_RB2); Ladder3pt_dual(array3, array6, engine.param.BOB, R, array2); } engine.isogeny.Double(R, R, array2, engine.param.OALICE_BITS); } internal void Compress_PKA_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] a24, uint[] rs, byte[] CompressedPKA) { ulong[] array = new ulong[engine.param.NWORDS_ORDER]; ulong[] array2 = new ulong[engine.param.NWORDS_ORDER]; ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2add(a24, a24, array3); engine.fpx.fp2add(array3, array3, array3); engine.fpx.fpsubPRIME(array3[0], engine.param.Montgomery_one, array3[0]); engine.fpx.fpsubPRIME(array3[0], engine.param.Montgomery_one, array3[0]); uint num = engine.fpx.mod3(d1); engine.fpx.to_Montgomery_mod_order(c0, c0, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.to_Montgomery_mod_order(c1, c1, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.to_Montgomery_mod_order(d0, d0, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.to_Montgomery_mod_order(d1, d1, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); if (num != 0) { engine.fpx.Montgomery_inversion_mod_order_bingcd(d1, array2, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.Montgomery_neg(d0, engine.param.Bob_order); engine.fpx.Montgomery_multiply_mod_order(d0, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, 0, engine.param.ORDER_B_ENCODED_BYTES); engine.fpx.Montgomery_neg(c1, engine.param.Bob_order); engine.fpx.Montgomery_multiply_mod_order(c1, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, engine.param.ORDER_B_ENCODED_BYTES, engine.param.ORDER_B_ENCODED_BYTES); engine.fpx.Montgomery_multiply_mod_order(c0, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, 2 * engine.param.ORDER_B_ENCODED_BYTES, engine.param.ORDER_B_ENCODED_BYTES); CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] = 0; } else { engine.fpx.Montgomery_inversion_mod_order_bingcd(d0, array2, engine.param.Bob_order, engine.param.Montgomery_RB2, engine.param.Montgomery_RB1); engine.fpx.Montgomery_neg(d1, engine.param.Bob_order); engine.fpx.Montgomery_multiply_mod_order(d1, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, 0, engine.param.ORDER_B_ENCODED_BYTES); engine.fpx.Montgomery_multiply_mod_order(c1, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, engine.param.ORDER_B_ENCODED_BYTES, engine.param.ORDER_B_ENCODED_BYTES); engine.fpx.Montgomery_neg(c0, engine.param.Bob_order); engine.fpx.Montgomery_multiply_mod_order(c0, array2, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.from_Montgomery_mod_order(array, array, engine.param.Bob_order, engine.param.Montgomery_RB2); engine.fpx.encode_to_bytes(array, CompressedPKA, 2 * engine.param.ORDER_B_ENCODED_BYTES, engine.param.ORDER_B_ENCODED_BYTES); CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] = 128; } engine.fpx.fp2_encode(array3, CompressedPKA, 3 * engine.param.ORDER_B_ENCODED_BYTES); CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] |= (byte)rs[0]; CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 1] = (byte)rs[1]; CompressedPKA[3 * engine.param.ORDER_B_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 2] = (byte)rs[2]; } internal uint EphemeralKeyGeneration_A_extended(byte[] PrivateKeyA, byte[] CompressedPKA) { uint[] array = new uint[3]; int[] d = new int[engine.param.DLEN_3]; ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][][] as = SikeUtilities.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD); ulong[][][] f = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD); ulong[] c = new ulong[engine.param.NWORDS_ORDER]; ulong[] d2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] c2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] d3 = new ulong[engine.param.NWORDS_ORDER]; PointProjFull[] array2 = new PointProjFull[2] { new PointProjFull(engine.param.NWORDS_FIELD), new PointProjFull(engine.param.NWORDS_FIELD) }; FullIsogeny_A_dual(PrivateKeyA, as, a, 1); BuildOrdinary3nBasis_dual(a, as, array2, array, array, 2); Tate3_pairings(array2, f); Dlogs3_dual(f, d, d2, c, d3, c2); Compress_PKA_dual(d2, c, d3, c2, a, array, CompressedPKA); return 0; } private uint EphemeralKeyGeneration_A(byte[] PrivateKeyA, byte[] CompressedPKA) { uint[] array = new uint[3]; int[] d = new int[engine.param.DLEN_3]; ulong[] c = new ulong[engine.param.NWORDS_ORDER]; ulong[] d2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] c2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] d3 = new ulong[engine.param.NWORDS_ORDER]; ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] f = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD); ulong[][][][] as = SikeUtilities.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD); PointProjFull[] array2 = new PointProjFull[2]; FullIsogeny_A_dual(PrivateKeyA, as, a, 0); BuildOrdinary3nBasis_dual(a, as, array2, array, array, 2); Tate3_pairings(array2, f); Dlogs3_dual(f, d, d2, c, d3, c2); Compress_PKA_dual(d2, c, d3, c2, a, array, CompressedPKA); return 0; } internal uint EphemeralSecretAgreement_B(byte[] PrivateKeyB, byte[] PKA, byte[] SharedSecretB) { uint num = 0; uint num2 = 0; uint num3 = 0; uint[] array = new uint[engine.param.MAX_INT_POINTS_BOB]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj[] array4 = new PointProj[engine.param.MAX_INT_POINTS_BOB]; ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD); ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PKADecompression_dual(PrivateKeyB, PKA, pointProj, a); engine.fpx.fp2copy(a, array6); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, engine.param.Montgomery_one, array3[0]); engine.fpx.fp2add(array6, array3, array2); engine.fpx.fp2sub(array6, array3, array3); num2 = 0; for (uint num4 = 1; num4 < engine.param.MAX_Bob; num4++) { uint num7; for (; num2 < engine.param.MAX_Bob - num4; num2 += num7) { array4[num3] = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.fp2copy(pointProj.X, array4[num3].X); engine.fpx.fp2copy(pointProj.Z, array4[num3].Z); array[num3++] = num2; num7 = engine.param.strat_Bob[num++]; engine.isogeny.XTplE(pointProj, pointProj, array3, array2, num7); } engine.isogeny.Get3Isog(pointProj, array3, array2, coeff); for (uint num8 = 0; num8 < num3; num8++) { engine.isogeny.Eval3Isog(array4[num8], coeff); } engine.fpx.fp2copy(array4[num3 - 1].X, pointProj.X); engine.fpx.fp2copy(array4[num3 - 1].Z, pointProj.Z); num2 = array[num3 - 1]; num3--; } engine.isogeny.Get3Isog(pointProj, array3, array2, coeff); engine.fpx.fp2add(array2, array3, array6); engine.fpx.fp2add(array6, array6, array6); engine.fpx.fp2sub(array2, array3, array2); engine.isogeny.JInv(array6, array2, array5); engine.fpx.fp2_encode(array5, SharedSecretB, 0); return 0; } internal void BuildEntangledXonly(ulong[][] A, PointProj[] R, byte[] qnr, byte[] ind) { ulong[] s = new ulong[engine.param.NWORDS_FIELD]; ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); uint num = 0; ulong[][] b; if (engine.fpx.is_sqr_fp2(A, s)) { b = engine.param.table_v_qnr; qnr[0] = 1; } else { b = engine.param.table_v_qr; qnr[0] = 0; } ind[0] = 0; do { engine.fpx.fp2mul_mont(A, b, num, R[0].X); num += 2; engine.fpx.fp2neg(R[0].X); engine.fpx.fp2add(R[0].X, A, array2); engine.fpx.fp2mul_mont(R[0].X, array2, array2); engine.fpx.fpaddPRIME(array2[0], engine.param.Montgomery_one, array2[0]); engine.fpx.fp2mul_mont(R[0].X, array2, array2); ind[0]++; } while (!engine.fpx.is_sqr_fp2(array2, s)); ind[0]--; if (qnr[0] == 1) engine.fpx.fpcopy(engine.param.table_r_qnr[ind[0]], 0, array[0]); else engine.fpx.fpcopy(engine.param.table_r_qr[ind[0]], 0, array[0]); engine.fpx.fp2add(R[0].X, A, R[1].X); engine.fpx.fp2neg(R[1].X); engine.fpx.fp2sub(R[0].X, R[1].X, R[2].Z); engine.fpx.fp2sqr_mont(R[2].Z, R[2].Z); engine.fpx.fpcopy(array[0], 0, array[1]); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array[0], array[0]); engine.fpx.fp2sqr_mont(array, array); engine.fpx.fp2mul_mont(array2, array, R[2].X); } internal void RecoverY(ulong[][] A, PointProj[] xs, PointProjFull[] Rs) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fp2mul_mont(xs[2].X, xs[1].Z, array); engine.fpx.fp2mul_mont(xs[1].X, xs[2].Z, array2); engine.fpx.fp2mul_mont(xs[1].X, xs[2].X, array3); engine.fpx.fp2mul_mont(xs[1].Z, xs[2].Z, array4); engine.fpx.fp2sqr_mont(xs[1].X, array5); engine.fpx.fp2sqr_mont(xs[1].Z, Rs[1].X); engine.fpx.fp2sub(array3, array4, Rs[1].Y); engine.fpx.fp2mul_mont(xs[1].X, Rs[1].Y, Rs[1].Y); engine.fpx.fp2add(array5, Rs[1].X, array5); engine.fpx.fp2mul_mont(xs[2].Z, array5, array5); engine.fpx.fp2mul_mont(A, array2, Rs[1].X); engine.fpx.fp2sub(array, array2, Rs[1].Z); engine.fpx.fp2mul_mont(Rs[0].X, Rs[1].Z, array); engine.fpx.fp2add(array3, Rs[1].X, array2); engine.fpx.fp2add(array2, array2, array2); engine.fpx.fp2sub(array, array2, array); engine.fpx.fp2mul_mont(xs[1].Z, array, array); engine.fpx.fp2sub(array, array5, array); engine.fpx.fp2mul_mont(Rs[0].X, array, array); engine.fpx.fp2add(array, Rs[1].Y, Rs[1].Y); engine.fpx.fp2mul_mont(Rs[0].Y, array4, array); engine.fpx.fp2mul_mont(xs[1].X, array, Rs[1].X); engine.fpx.fp2add(Rs[1].X, Rs[1].X, Rs[1].X); engine.fpx.fp2mul_mont(xs[1].Z, array, Rs[1].Z); engine.fpx.fp2add(Rs[1].Z, Rs[1].Z, Rs[1].Z); engine.fpx.fp2inv_mont_bingcd(Rs[1].Z); engine.fpx.fp2mul_mont(Rs[1].X, Rs[1].Z, Rs[1].X); engine.fpx.fp2mul_mont(Rs[1].Y, Rs[1].Z, Rs[1].Y); } internal void BuildOrdinary2nBasis_dual(ulong[][] A, ulong[][][][] Ds, PointProjFull[] Rs, byte[] qnr, byte[] ind) { ulong[] array = new ulong[engine.param.NWORDS_FIELD]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PointProj[] array3 = new PointProj[3] { new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD) }; BuildEntangledXonly(A, array3, qnr, ind); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[1].Z[0]); for (uint num = 0; num < engine.param.MAX_Bob; num++) { engine.isogeny.Eval3Isog(array3[0], Ds[engine.param.MAX_Bob - 1 - num]); engine.isogeny.Eval3Isog(array3[1], Ds[engine.param.MAX_Bob - 1 - num]); engine.isogeny.Eval3Isog(array3[2], Ds[engine.param.MAX_Bob - 1 - num]); } engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array2[0]); engine.fpx.fpaddPRIME(array2[0], array2[0], array); engine.fpx.fpaddPRIME(array, array, array2[0]); engine.fpx.fpaddPRIME(array2[0], array, array2[0]); engine.isogeny.CompleteMPoint(array2, array3[0], Rs[0]); RecoverY(array2, array3, Rs); } internal void FullIsogeny_B_dual(byte[] PrivateKeyB, ulong[][][][] Ds, ulong[][] A) { PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); PointProj[] array = new PointProj[engine.param.MAX_INT_POINTS_BOB]; ulong[][] xP = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] xQ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD); uint num = 0; uint num2 = 0; uint num3 = 0; uint[] array5 = new uint[engine.param.MAX_INT_POINTS_BOB]; ulong[] array6 = new ulong[engine.param.NWORDS_ORDER]; init_basis(engine.param.B_gen, xP, xQ, array2); engine.fpx.fpcopy(engine.param.XQB3, 0, pointProj2.X[0]); engine.fpx.fpcopy(engine.param.XQB3, engine.param.NWORDS_FIELD, pointProj2.X[1]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, pointProj2.Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array3[0]); engine.fpx.fp2add(array3, array3, array3); engine.fpx.fp2add(array3, array3, array4); engine.fpx.fp2add(array3, array4, A); engine.fpx.fp2add(array4, array4, array3); engine.fpx.decode_to_digits(PrivateKeyB, 0, array6, engine.param.SECRETKEY_B_BYTES, engine.param.NWORDS_ORDER); engine.isogeny.LADDER3PT(xP, xQ, array2, array6, engine.param.BOB, pointProj, A); num = 0; for (uint num4 = 1; num4 < engine.param.MAX_Bob; num4++) { uint num7; for (; num < engine.param.MAX_Bob - num4; num += num7) { array[num2] = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.fp2copy(pointProj.X, array[num2].X); engine.fpx.fp2copy(pointProj.Z, array[num2].Z); array5[num2++] = num; num7 = engine.param.strat_Bob[num3++]; engine.isogeny.XTplE(pointProj, pointProj, array4, array3, num7); } engine.isogeny.Get3Isog(pointProj, array4, array3, coeff); for (uint num8 = 0; num8 < num2; num8++) { engine.isogeny.Eval3Isog(array[num8], coeff); } engine.isogeny.Eval3Isog(pointProj2, coeff); engine.fpx.fp2sub(pointProj2.X, pointProj2.Z, Ds[num4 - 1][0]); engine.fpx.fp2add(pointProj2.X, pointProj2.Z, Ds[num4 - 1][1]); engine.fpx.fp2copy(array[num2 - 1].X, pointProj.X); engine.fpx.fp2copy(array[num2 - 1].Z, pointProj.Z); num = array5[num2 - 1]; num2--; } engine.isogeny.Get3Isog(pointProj, array4, array3, coeff); engine.isogeny.Eval3Isog(pointProj2, coeff); engine.fpx.fp2sub(pointProj2.X, pointProj2.Z, Ds[engine.param.MAX_Bob - 1][0]); engine.fpx.fp2add(pointProj2.X, pointProj2.Z, Ds[engine.param.MAX_Bob - 1][1]); engine.fpx.fp2add(array3, array4, A); engine.fpx.fp2sub(array3, array4, array3); engine.fpx.fp2inv_mont_bingcd(array3); engine.fpx.fp2mul_mont(array3, A, A); engine.fpx.fp2add(A, A, A); } internal void Dlogs2_dual(ulong[][][] f, int[] D, ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1) { solve_dlog(f[0], D, d0, 2); solve_dlog(f[2], D, c0, 2); solve_dlog(f[1], D, d1, 2); solve_dlog(f[3], D, c1, 2); engine.fpx.mp_sub(engine.param.Alice_order, c0, c0, engine.param.NWORDS_ORDER); engine.fpx.mp_sub(engine.param.Alice_order, c1, c1, engine.param.NWORDS_ORDER); } internal void BuildEntangledXonly_Decomp(ulong[][] A, PointProj[] R, uint qnr, uint ind) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] b = (qnr != 1) ? engine.param.table_v_qr : engine.param.table_v_qnr; if (ind >= engine.param.TABLE_V_LEN / 2) ind = 0; engine.fpx.fp2mul_mont(A, b, ind * 2, R[0].X); engine.fpx.fp2neg(R[0].X); engine.fpx.fp2add(R[0].X, A, array2); engine.fpx.fp2mul_mont(R[0].X, array2, array2); engine.fpx.fpaddPRIME(array2[0], engine.param.Montgomery_one, array2[0]); engine.fpx.fp2mul_mont(R[0].X, array2, array2); if (qnr == 1) engine.fpx.fpcopy(engine.param.table_r_qnr[ind], 0, array[0]); else engine.fpx.fpcopy(engine.param.table_r_qr[ind], 0, array[0]); engine.fpx.fp2add(R[0].X, A, R[1].X); engine.fpx.fp2neg(R[1].X); engine.fpx.fp2sub(R[0].X, R[1].X, R[2].Z); engine.fpx.fp2sqr_mont(R[2].Z, R[2].Z); engine.fpx.fpcopy(array[0], 0, array[1]); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array[0], array[0]); engine.fpx.fp2sqr_mont(array, array); engine.fpx.fp2mul_mont(array2, array, R[2].X); } internal void PKBDecompression_extended(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A, byte[] tphiBKA_t, uint tphiBKA_tOffset) { ulong num = ulong.MaxValue; ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[] array3 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array4 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array5 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array6 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array7 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array8 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array9 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array10 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array11 = new ulong[engine.param.NWORDS_ORDER]; PointProj[] array12 = new PointProj[3] { new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD), new PointProj(engine.param.NWORDS_FIELD) }; num >>= (int)(engine.param.MAXBITS_ORDER - engine.param.OALICE_BITS); engine.fpx.fp2_decode(CompressedPKB, A, 4 * engine.param.ORDER_A_ENCODED_BYTES); uint qnr = (uint)(CompressedPKB[4 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] & 1); uint ind = CompressedPKB[4 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 1]; BuildEntangledXonly_Decomp(A, array12, qnr, ind); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array12[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array12[1].Z[0]); engine.fpx.fpaddPRIME(A[0], engine.param.Montgomery_one, array[0]); engine.fpx.fpcopy(A[1], 0, array[1]); engine.fpx.fpaddPRIME(array[0], engine.param.Montgomery_one, array[0]); engine.fpx.fp2div2(array, array); engine.fpx.fp2div2(array, array); engine.fpx.decode_to_digits(SecretKeyA, SecretKeyAOffset, array7, engine.param.SECRETKEY_A_BYTES, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, 0, array8, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, array10, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, array9, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, 3 * engine.param.ORDER_A_ENCODED_BYTES, array11, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); if ((array8[0] & 1) == 1) { engine.fpx.multiply(array7, array11, array3, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array3, array10, array3, engine.param.NWORDS_ORDER); array3[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.multiply(array7, array9, array4, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array4, array8, array4, engine.param.NWORDS_ORDER); array4[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.inv_mod_orderA(array4, array5); engine.fpx.multiply(array3, array5, array6, engine.param.NWORDS_ORDER); array6[engine.param.NWORDS_ORDER - 1] &= num; Ladder3pt_dual(array12, array6, engine.param.ALICE, R, array); } else { engine.fpx.multiply(array7, array9, array3, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array3, array8, array3, engine.param.NWORDS_ORDER); array3[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.multiply(array7, array11, array4, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array4, array10, array4, engine.param.NWORDS_ORDER); array4[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.inv_mod_orderA(array4, array5); engine.fpx.multiply(array5, array3, array6, engine.param.NWORDS_ORDER); array6[engine.param.NWORDS_ORDER - 1] &= num; engine.isogeny.SwapPoints(array12[0], array12[1], ulong.MaxValue); Ladder3pt_dual(array12, array6, engine.param.ALICE, R, array); } engine.fpx.fp2div2(A, array2); engine.isogeny.XTplEFast(R, R, array2, engine.param.OBOB_EXPON); engine.fpx.fp2_encode(R.X, tphiBKA_t, tphiBKA_tOffset); engine.fpx.fp2_encode(R.Z, tphiBKA_t, tphiBKA_tOffset + engine.param.FP2_ENCODED_BYTES); engine.fpx.encode_to_bytes(array5, tphiBKA_t, tphiBKA_tOffset + 2 * engine.param.FP2_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); } internal void Compress_PKB_dual_extended(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) { ulong num = ulong.MaxValue; ulong[] array = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array2 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array3 = new ulong[2 * engine.param.NWORDS_ORDER]; num >>= (int)(engine.param.MAXBITS_ORDER - engine.param.OALICE_BITS); engine.fpx.multiply(c0, d1, array, engine.param.NWORDS_ORDER); engine.fpx.multiply(c1, d0, array2, engine.param.NWORDS_ORDER); engine.fpx.Montgomery_neg(array2, engine.param.Alice_order); engine.fpx.mp_add(array, array2, array2, engine.param.NWORDS_ORDER); array2[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.inv_mod_orderA(array2, array3); engine.fpx.multiply(d1, array3, array, engine.param.NWORDS_ORDER); array[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.encode_to_bytes(array, CompressedPKB, 0, engine.param.ORDER_A_ENCODED_BYTES); engine.fpx.Montgomery_neg(d0, engine.param.Alice_order); engine.fpx.multiply(d0, array3, array, engine.param.NWORDS_ORDER); array[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.encode_to_bytes(array, CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); engine.fpx.Montgomery_neg(c1, engine.param.Alice_order); engine.fpx.multiply(c1, array3, array, engine.param.NWORDS_ORDER); array[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.encode_to_bytes(array, CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); engine.fpx.multiply(c0, array3, array, engine.param.NWORDS_ORDER); array[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.encode_to_bytes(array, CompressedPKB, 3 * engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); engine.fpx.fp2_encode(A, CompressedPKB, 4 * engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[4 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] = qnr[0]; CompressedPKB[4 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 1] = ind[0]; } internal void PKBDecompression(byte[] SecretKeyA, uint SecretKeyAOffset, byte[] CompressedPKB, PointProj R, ulong[][] A) { ulong num = ulong.MaxValue; ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[] array2 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array3 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array4 = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array5 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array6 = new ulong[engine.param.NWORDS_ORDER]; PointProj[] array7 = new PointProj[3]; num >>= (int)(engine.param.MAXBITS_ORDER - engine.param.OALICE_BITS); array4[0] = 1; engine.fpx.fp2_decode(CompressedPKB, A, 3 * engine.param.ORDER_A_ENCODED_BYTES); uint num2 = (uint)(CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] >> 7); uint qnr = (uint)(CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] & 1); uint ind = CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 1]; BuildEntangledXonly_Decomp(A, array7, qnr, ind); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array7[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array7[1].Z[0]); engine.fpx.fpaddPRIME(A[0], engine.param.Montgomery_one, array[0]); engine.fpx.fpcopy(A[1], 0, array[1]); engine.fpx.fpaddPRIME(array[0], engine.param.Montgomery_one, array[0]); engine.fpx.fp2div2(array, array); engine.fpx.fp2div2(array, array); engine.fpx.decode_to_digits(SecretKeyA, SecretKeyAOffset, array5, engine.param.SECRETKEY_A_BYTES, engine.param.NWORDS_ORDER); engine.isogeny.SwapPoints(array7[0], array7[1], (ulong)(0 - (long)num2)); if (num2 == 0) { engine.fpx.decode_to_digits(CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.multiply(array5, array6, array2, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array2, array4, array2, engine.param.NWORDS_ORDER); array2[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.inv_mod_orderA(array2, array3); engine.fpx.decode_to_digits(CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.multiply(array5, array6, array2, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, 0, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array6, array2, array2, engine.param.NWORDS_ORDER); engine.fpx.multiply(array2, array3, array4, engine.param.NWORDS_ORDER); array4[engine.param.NWORDS_ORDER - 1] &= num; Ladder3pt_dual(array7, array4, engine.param.ALICE, R, array); } else { engine.fpx.decode_to_digits(CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.multiply(array5, array6, array2, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array2, array4, array2, engine.param.NWORDS_ORDER); array2[engine.param.NWORDS_ORDER - 1] &= num; engine.fpx.inv_mod_orderA(array2, array3); engine.fpx.decode_to_digits(CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.multiply(array5, array6, array2, engine.param.NWORDS_ORDER); engine.fpx.decode_to_digits(CompressedPKB, 0, array6, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.fpx.mp_add(array6, array2, array2, engine.param.NWORDS_ORDER); engine.fpx.multiply(array2, array3, array4, engine.param.NWORDS_ORDER); array4[engine.param.NWORDS_ORDER - 1] &= num; Ladder3pt_dual(array7, array4, engine.param.ALICE, R, array); } engine.fpx.fp2div2(A, array); engine.isogeny.XTplEFast(R, R, array, engine.param.OBOB_EXPON); } internal void Compress_PKB_dual(ulong[] d0, ulong[] c0, ulong[] d1, ulong[] c1, ulong[][] A, byte[] qnr, byte[] ind, byte[] CompressedPKB) { ulong[] array = new ulong[2 * engine.param.NWORDS_ORDER]; ulong[] array2 = new ulong[engine.param.NWORDS_ORDER]; if ((d1[0] & 1) == 1) { engine.fpx.inv_mod_orderA(d1, array2); engine.fpx.Montgomery_neg(d0, engine.param.Alice_order); engine.fpx.multiply(d0, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, 0, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; engine.fpx.Montgomery_neg(c1, engine.param.Alice_order); engine.fpx.multiply(c1, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[2 * engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; engine.fpx.multiply(c0, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] = 0; } else { engine.fpx.inv_mod_orderA(d0, array2); engine.fpx.Montgomery_neg(d1, engine.param.Alice_order); engine.fpx.multiply(d1, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, 0, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; engine.fpx.multiply(c1, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[2 * engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; engine.fpx.Montgomery_neg(c0, engine.param.Alice_order); engine.fpx.multiply(c0, array2, array, engine.param.NWORDS_ORDER); engine.fpx.encode_to_bytes(array, CompressedPKB, 2 * engine.param.ORDER_A_ENCODED_BYTES, engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES - 1] &= (byte)engine.param.MASK_ALICE; CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] = 128; } engine.fpx.fp2_encode(A, CompressedPKB, 3 * engine.param.ORDER_A_ENCODED_BYTES); CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES] |= qnr[0]; CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 1] = ind[0]; CompressedPKB[3 * engine.param.ORDER_A_ENCODED_BYTES + engine.param.FP2_ENCODED_BYTES + 2] = 0; } internal uint EphemeralKeyGeneration_B_extended(byte[] PrivateKeyB, byte[] CompressedPKB, uint sike) { byte[] qnr = new byte[1]; byte[] ind = new byte[1]; int[] d = new int[engine.param.DLEN_2]; ulong[] c = new ulong[engine.param.NWORDS_ORDER]; ulong[] d2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] c2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] d3 = new ulong[engine.param.NWORDS_ORDER]; ulong[][][][] ds = SikeUtilities.InitArray(engine.param.MAX_Bob, 2, 2, engine.param.NWORDS_FIELD); ulong[][][] array = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD); ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PointProjFull[] array2 = new PointProjFull[2] { new PointProjFull(engine.param.NWORDS_FIELD), new PointProjFull(engine.param.NWORDS_FIELD) }; PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); FullIsogeny_B_dual(PrivateKeyB, ds, a); BuildOrdinary2nBasis_dual(a, ds, array2, qnr, ind); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array2[0].X[0], array2[0].X[0]); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array2[0].X[0], array2[0].X[0]); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array2[1].X[0], array2[1].X[0]); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, array2[1].X[0], array2[1].X[0]); Fpx fpx = engine.fpx; ulong[] a_basis_zero = engine.param.A_basis_zero; uint nWORDS_FIELD = engine.param.NWORDS_FIELD; fpx.fpcopy(a_basis_zero, 0, pointProj.X[0]); engine.fpx.fpcopy(engine.param.A_basis_zero, engine.param.NWORDS_FIELD, pointProj.X[1]); engine.fpx.fpcopy(engine.param.A_basis_zero, 2 * engine.param.NWORDS_FIELD, pointProj.Z[0]); engine.fpx.fpcopy(engine.param.A_basis_zero, 3 * engine.param.NWORDS_FIELD, pointProj.Z[1]); engine.fpx.fpcopy(engine.param.A_basis_zero, 4 * engine.param.NWORDS_FIELD, pointProj2.X[0]); engine.fpx.fpcopy(engine.param.A_basis_zero, 5 * engine.param.NWORDS_FIELD, pointProj2.X[1]); engine.fpx.fpcopy(engine.param.A_basis_zero, 6 * engine.param.NWORDS_FIELD, pointProj2.Z[0]); engine.fpx.fpcopy(engine.param.A_basis_zero, 7 * engine.param.NWORDS_FIELD, pointProj2.Z[1]); Tate2_pairings(pointProj, pointProj2, array2, array); engine.fpx.fp2correction(array[0]); engine.fpx.fp2correction(array[1]); engine.fpx.fp2correction(array[2]); engine.fpx.fp2correction(array[3]); Dlogs2_dual(array, d, d2, c, d3, c2); if (sike == 1) Compress_PKB_dual_extended(d2, c, d3, c2, a, qnr, ind, CompressedPKB); else Compress_PKB_dual(d2, c, d3, c2, a, qnr, ind, CompressedPKB); return 0; } internal uint EphemeralKeyGeneration_B(byte[] PrivateKeyB, byte[] CompressedPKB) { return EphemeralKeyGeneration_B_extended(PrivateKeyB, CompressedPKB, 0); } internal uint EphemeralSecretAgreement_A_extended(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA, uint sike) { uint num = 0; uint num2 = 0; uint num3 = 0; uint[] array = new uint[engine.param.MAX_INT_POINTS_ALICE]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj[] array4 = new PointProj[engine.param.MAX_INT_POINTS_ALICE]; ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] coeff = SikeUtilities.InitArray(5, 2, engine.param.NWORDS_FIELD); if (sike == 1) PKBDecompression_extended(PrivateKeyA, PrivateKeyAOffset, PKB, pointProj, a, SharedSecretA, engine.param.FP2_ENCODED_BYTES); else PKBDecompression(PrivateKeyA, PrivateKeyAOffset, PKB, pointProj, a); engine.fpx.fp2copy(a, array6); engine.fpx.fpaddPRIME(engine.param.Montgomery_one, engine.param.Montgomery_one, array3[0]); engine.fpx.fp2add(array6, array3, array2); engine.fpx.fpaddPRIME(array3[0], array3[0], array3[0]); if (engine.param.OALICE_BITS % 2 == 1) { PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); engine.isogeny.XDblE(pointProj, pointProj2, array2, array3, engine.param.OALICE_BITS - 1); engine.isogeny.Get2Isog(pointProj2, array2, array3); engine.isogeny.Eval2Isog(pointProj, pointProj2); } num2 = 0; for (uint num4 = 1; num4 < engine.param.MAX_Alice; num4++) { uint num7; for (; num2 < engine.param.MAX_Alice - num4; num2 += num7) { array4[num3] = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.fp2copy(pointProj.X, array4[num3].X); engine.fpx.fp2copy(pointProj.Z, array4[num3].Z); array[num3++] = num2; num7 = engine.param.strat_Alice[num++]; engine.isogeny.XDblE(pointProj, pointProj, array2, array3, 2 * num7); } engine.isogeny.Get4Isog(pointProj, array2, array3, coeff); for (uint num8 = 0; num8 < num3; num8++) { engine.isogeny.Eval4Isog(array4[num8], coeff); } engine.fpx.fp2copy(array4[num3 - 1].X, pointProj.X); engine.fpx.fp2copy(array4[num3 - 1].Z, pointProj.Z); num2 = array[num3 - 1]; num3--; } engine.isogeny.Get4Isog(pointProj, array2, array3, coeff); engine.fpx.fp2add(array2, array2, array2); engine.fpx.fp2sub(array2, array3, array2); engine.fpx.fp2add(array2, array2, array2); engine.isogeny.JInv(array2, array3, array5); engine.fpx.fp2_encode(array5, SharedSecretA, 0); return 0; } private uint EphemeralSecretAgreement_A(byte[] PrivateKeyA, uint PrivateKeyAOffset, byte[] PKB, byte[] SharedSecretA) { return EphemeralSecretAgreement_A_extended(PrivateKeyA, PrivateKeyAOffset, PKB, SharedSecretA, 0); } internal byte validate_ciphertext(byte[] ephemeralsk_, byte[] CompressedPKB, byte[] xKA, uint xKAOffset, byte[] tphiBKA_t, uint tphiBKA_tOffset) { PointProj[] array = new PointProj[3]; PointProj[] array2 = new PointProj[engine.param.MAX_INT_POINTS_BOB]; array[0] = new PointProj(engine.param.NWORDS_FIELD); array[1] = new PointProj(engine.param.NWORDS_FIELD); array[2] = new PointProj(engine.param.NWORDS_FIELD); PointProj pointProj = new PointProj(engine.param.NWORDS_FIELD); PointProj pointProj2 = new PointProj(engine.param.NWORDS_FIELD); ulong[][] xP = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] xQ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array7 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array8 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array9 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD); uint num = 0; uint num2 = 0; uint num3 = 0; uint[] array10 = new uint[engine.param.MAX_INT_POINTS_BOB]; ulong[] array11 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array12 = new ulong[engine.param.NWORDS_ORDER]; engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array9[0]); init_basis(engine.param.B_gen, xP, xQ, array3); engine.fpx.fp2_decode(xKA, array[0].X, xKAOffset); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array[0].Z[0]); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array4[0]); engine.fpx.fp2add(array4, array4, array4); engine.fpx.fp2add(array4, array4, array5); engine.fpx.fp2add(array4, array5, array6); engine.fpx.fp2add(array5, array5, array4); engine.fpx.decode_to_digits(ephemeralsk_, 0, array12, engine.param.SECRETKEY_B_BYTES, engine.param.NWORDS_ORDER); engine.isogeny.LADDER3PT(xP, xQ, array3, array12, engine.param.BOB, pointProj, array6); num = 0; for (uint num4 = 1; num4 < engine.param.MAX_Bob; num4++) { uint num7; for (; num < engine.param.MAX_Bob - num4; num += num7) { array2[num2] = new PointProj(engine.param.NWORDS_FIELD); engine.fpx.fp2copy(pointProj.X, array2[num2].X); engine.fpx.fp2copy(pointProj.Z, array2[num2].Z); array10[num2++] = num; num7 = engine.param.strat_Bob[num3++]; engine.isogeny.XTplE(pointProj, pointProj, array5, array4, num7); } engine.isogeny.Get3Isog(pointProj, array5, array4, coeff); for (uint num8 = 0; num8 < num2; num8++) { engine.isogeny.Eval3Isog(array2[num8], coeff); } engine.isogeny.Eval3Isog(array[0], coeff); engine.fpx.fp2copy(array2[num2 - 1].X, pointProj.X); engine.fpx.fp2copy(array2[num2 - 1].Z, pointProj.Z); num = array10[num2 - 1]; num2--; } engine.isogeny.Get3Isog(pointProj, array5, array4, coeff); engine.isogeny.Eval3Isog(array[0], coeff); engine.fpx.fp2_decode(CompressedPKB, array6, 4 * engine.param.ORDER_A_ENCODED_BYTES); engine.fpx.fp2_decode(tphiBKA_t, pointProj2.X, tphiBKA_tOffset); engine.fpx.fp2_decode(tphiBKA_t, pointProj2.Z, tphiBKA_tOffset + engine.param.FP2_ENCODED_BYTES); engine.fpx.decode_to_digits(tphiBKA_t, tphiBKA_tOffset + 2 * engine.param.FP2_ENCODED_BYTES, array11, engine.param.ORDER_A_ENCODED_BYTES, engine.param.NWORDS_ORDER); engine.isogeny.Ladder(array[0], array11, array6, engine.param.OALICE_BITS, pointProj); engine.fpx.fp2mul_mont(pointProj.X, pointProj2.Z, array7); engine.fpx.fp2mul_mont(pointProj.Z, pointProj2.X, array8); return engine.fpx.cmp_f2elm(array7, array8); } internal void solve_dlog(ulong[][] r, int[] D, ulong[] d, uint ell) { switch (ell) { case 2: if ((long)engine.param.OALICE_BITS % (long)(int)engine.param.W_2 == 0) Traverse_w_div_e_fullsigned(r, 0, 0, engine.param.PLEN_2 - 1, engine.param.ph2_path, engine.param.ph2_T, D, engine.param.DLEN_2, engine.param.ELL2_W, engine.param.W_2); else Traverse_w_notdiv_e_fullsigned(r, 0, 0, engine.param.PLEN_2 - 1, engine.param.ph2_path, engine.param.ph2_T1, engine.param.ph2_T2, D, engine.param.DLEN_2, ell, engine.param.ELL2_W, engine.param.ELL2_EMODW, engine.param.W_2, engine.param.OALICE_BITS); from_base(D, d, engine.param.DLEN_2, engine.param.ELL2_W); break; case 3: if ((long)engine.param.OBOB_EXPON % (long)(int)engine.param.W_3 == 0) Traverse_w_div_e_fullsigned(r, 0, 0, engine.param.PLEN_3 - 1, engine.param.ph3_path, engine.param.ph3_T, D, engine.param.DLEN_3, engine.param.ELL3_W, engine.param.W_3); else Traverse_w_notdiv_e_fullsigned(r, 0, 0, engine.param.PLEN_3 - 1, engine.param.ph3_path, engine.param.ph3_T1, engine.param.ph3_T2, D, engine.param.DLEN_3, ell, engine.param.ELL3_W, engine.param.ELL3_EMODW, engine.param.W_3, engine.param.OBOB_EXPON); from_base(D, d, engine.param.DLEN_3, engine.param.ELL3_W); break; } } private void from_base(int[] D, ulong[] r, uint Dlen, uint baseNum) { ulong[] array = new ulong[engine.param.NWORDS_ORDER]; ulong[] array2 = new ulong[engine.param.NWORDS_ORDER]; ulong[] array3 = new ulong[engine.param.NWORDS_ORDER]; array[0] = baseNum; if (D[Dlen - 1] < 0) { array2[0] = (ulong)(-D[Dlen - 1] * (int)array[0]); if ((baseNum & 1) == 0) { engine.fpx.Montgomery_neg(array2, engine.param.Alice_order); engine.fpx.copy_words(array2, r, engine.param.NWORDS_ORDER); } else engine.fpx.mp_sub(engine.param.Bob_order, array2, r, engine.param.NWORDS_ORDER); } else r[0] = (uint)D[Dlen - 1] * array[0]; for (uint num = Dlen - 2; num >= 1; num--) { uint num2 = baseNum; Arrays.Fill(array2, 0); if (D[num] < 0) { array2[0] = (ulong)(-D[num]); if ((baseNum & 1) == 0) engine.fpx.Montgomery_neg(array2, engine.param.Alice_order); else engine.fpx.mp_sub(engine.param.Bob_order, array2, array2, engine.param.NWORDS_ORDER); } else array2[0] = (uint)D[num]; engine.fpx.mp_add(r, array2, r, engine.param.NWORDS_ORDER); if ((baseNum & 1) != 0 && !engine.fpx.is_orderelm_lt(r, engine.param.Bob_order)) engine.fpx.mp_sub(r, engine.param.Bob_order, r, engine.param.NWORDS_ORDER); if ((baseNum & 1) == 0) { while (num2 > 1) { engine.fpx.mp_add(r, r, r, engine.param.NWORDS_ORDER); num2 /= 2; } } else { while (num2 > 1) { Arrays.Fill(array3, 0); engine.fpx.mp_add(r, r, array3, engine.param.NWORDS_ORDER); if (!engine.fpx.is_orderelm_lt(array3, engine.param.Bob_order)) engine.fpx.mp_sub(array3, engine.param.Bob_order, array3, engine.param.NWORDS_ORDER); engine.fpx.mp_add(r, array3, r, engine.param.NWORDS_ORDER); if (!engine.fpx.is_orderelm_lt(r, engine.param.Bob_order)) engine.fpx.mp_sub(r, engine.param.Bob_order, r, engine.param.NWORDS_ORDER); num2 /= 3; } } } Arrays.Fill(array2, 0); if (D[0] < 0) { array2[0] = (ulong)(-D[0]); if ((baseNum & 1) == 0) engine.fpx.Montgomery_neg(array2, engine.param.Alice_order); else engine.fpx.mp_sub(engine.param.Bob_order, array2, array2, engine.param.NWORDS_ORDER); } else array2[0] = (uint)D[0]; engine.fpx.mp_add(r, array2, r, engine.param.NWORDS_ORDER); if ((baseNum & 1) != 0 && !engine.fpx.is_orderelm_lt(r, engine.param.Bob_order)) engine.fpx.mp_sub(r, engine.param.Bob_order, r, engine.param.NWORDS_ORDER); } internal void Traverse_w_notdiv_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT1, ulong[] CT2, int[] D, uint Dlen, uint ell, uint ellw, uint ell_emodw, uint w, uint e) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); if (z > 1) { uint num = P[z]; engine.fpx.fp2copy(r, array); uint num2 = (j != 0) ? (w * (z - num)) : (e % w + w * (z - num - 1)); for (uint num3 = 0; num3 < num2; num3++) { if ((ell & 1) == 0) engine.fpx.sqr_Fp2_cycl(array, engine.param.Montgomery_one); else engine.fpx.cube_Fp2_cycl(array, engine.param.Montgomery_one); } Traverse_w_notdiv_e_fullsigned(array, j + (z - num), k, num, P, CT1, CT2, D, Dlen, ell, ellw, ell_emodw, w, e); engine.fpx.fp2copy(r, array); for (uint num4 = k; num4 < k + num; num4++) { if (D[num4] != 0) { if (j != 0) { if (D[num4] < 0) { engine.fpx.fp2copy(CT2, (uint)(engine.param.NWORDS_FIELD * (2 * (j + num4) * (ellw / 2) + 2 * (-D[num4] - 1))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fp2mul_mont(array, array2, array); } else engine.fpx.fp2mul_mont(array, CT2, (uint)(engine.param.NWORDS_FIELD * (2 * ((j + num4) * (ellw / 2) + (D[num4] - 1)))), array); } else if (D[num4] < 0) { engine.fpx.fp2copy(CT1, (uint)(engine.param.NWORDS_FIELD * (2 * ((j + num4) * (ellw / 2) + (-D[num4] - 1)))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fp2mul_mont(array, array2, array); } else { engine.fpx.fp2mul_mont(array, CT1, (uint)(engine.param.NWORDS_FIELD * (2 * ((j + num4) * (ellw / 2) + (D[num4] - 1)))), array); } } } Traverse_w_notdiv_e_fullsigned(array, j, k + num, z - num, P, CT1, CT2, D, Dlen, ell, ellw, ell_emodw, w, e); } else { engine.fpx.fp2copy(r, array); engine.fpx.fp2correction(array); if (engine.fpx.is_felm_zero(array[1]) && Fpx.subarrayEquals(array[0], engine.param.Montgomery_one, engine.param.NWORDS_FIELD)) D[k] = 0; else if (j != 0 || k != Dlen - 1) { uint num5 = 1; while (true) { if (num5 > ellw / 2) return; if (Fpx.subarrayEquals(array, CT2, engine.param.NWORDS_FIELD * (2 * (ellw / 2) * (Dlen - 1) + 2 * (num5 - 1)), 2 * engine.param.NWORDS_FIELD)) { D[k] = (int)(0 - num5); return; } engine.fpx.fp2copy(CT2, engine.param.NWORDS_FIELD * (2 * (ellw / 2 * (Dlen - 1) + (num5 - 1))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fpcorrectionPRIME(array2[1]); if (Fpx.subarrayEquals(array, array2, 2 * engine.param.NWORDS_FIELD)) break; num5++; } D[k] = (int)num5; } else { uint num6 = 1; while (true) { if (num6 > ell_emodw / 2) return; if (Fpx.subarrayEquals(array, CT1, engine.param.NWORDS_FIELD * (2 * (ellw / 2) * (Dlen - 1) + 2 * (num6 - 1)), 2 * engine.param.NWORDS_FIELD)) { D[k] = (int)(0 - num6); return; } engine.fpx.fp2copy(CT1, engine.param.NWORDS_FIELD * (2 * (ellw / 2 * (Dlen - 1) + (num6 - 1))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fpcorrectionPRIME(array2[1]); if (Fpx.subarrayEquals(array, array2, 2 * engine.param.NWORDS_FIELD)) break; num6++; } D[k] = (int)num6; } } } internal void Traverse_w_div_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT, int[] D, uint Dlen, uint ellw, uint w) { ulong[][] array = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); if (z > 1) { uint num = P[z]; engine.fpx.fp2copy(r, array); for (uint num2 = 0; num2 < z - num; num2++) { if ((ellw & 1) == 0) { for (uint num3 = 0; num3 < w; num3++) { engine.fpx.sqr_Fp2_cycl(array, engine.param.Montgomery_one); } } else { for (uint num4 = 0; num4 < w; num4++) { engine.fpx.cube_Fp2_cycl(array, engine.param.Montgomery_one); } } } Traverse_w_div_e_fullsigned(array, j + (z - num), k, num, P, CT, D, Dlen, ellw, w); engine.fpx.fp2copy(r, array); for (uint num5 = k; num5 < k + num; num5++) { if (D[num5] != 0) { if (D[num5] < 0) { engine.fpx.fp2copy(CT, (uint)(engine.param.NWORDS_FIELD * (2 * ((j + num5) * (ellw / 2) + (-D[num5] - 1)))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fp2mul_mont(array, array2, array); } else engine.fpx.fp2mul_mont(array, CT, (uint)(engine.param.NWORDS_FIELD * (2 * ((j + num5) * (ellw / 2) + (D[num5] - 1)))), array); } } Traverse_w_div_e_fullsigned(array, j, k + num, z - num, P, CT, D, Dlen, ellw, w); } else { engine.fpx.fp2copy(r, array); engine.fpx.fp2correction(array); if (engine.fpx.is_felm_zero(array[1]) && Fpx.subarrayEquals(array[0], engine.param.Montgomery_one, engine.param.NWORDS_FIELD)) D[k] = 0; else { uint num6 = 1; while (true) { if (num6 > ellw / 2) return; if (Fpx.subarrayEquals(array, CT, engine.param.NWORDS_FIELD * (2 * ((Dlen - 1) * (ellw / 2) + (num6 - 1))), 2 * engine.param.NWORDS_FIELD)) { D[k] = (int)(0 - num6); return; } engine.fpx.fp2copy(CT, engine.param.NWORDS_FIELD * (2 * ((Dlen - 1) * (ellw / 2) + (num6 - 1))), array2); engine.fpx.fpnegPRIME(array2[1]); engine.fpx.fpcorrectionPRIME(array2[1]); if (Fpx.subarrayEquals(array, array2, 2 * engine.param.NWORDS_FIELD)) break; num6++; } D[k] = (int)num6; } } } private void Tate3_pairings(PointProjFull[] Qj, ulong[][][] f) { ulong[] array = new ulong[engine.param.NWORDS_FIELD]; ulong[] array2 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array3 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array4 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array5 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array6 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array7 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array8 = new ulong[engine.param.NWORDS_FIELD]; ulong[] array9 = new ulong[engine.param.NWORDS_FIELD]; ulong[][][] array10 = SikeUtilities.InitArray(t_points, 2, engine.param.NWORDS_FIELD); ulong[][][] array11 = SikeUtilities.InitArray(2 * t_points, 2, engine.param.NWORDS_FIELD); ulong[][] array12 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array13 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array14 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array15 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array16 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array17 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array18 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array19 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array20 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array21 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array12[0]); for (uint num = 0; num < t_points; num++) { engine.fpx.fp2copy(array12, f[num]); engine.fpx.fp2copy(array12, f[num + t_points]); engine.fpx.fp2sqr_mont(Qj[num].X, array10[num]); } for (uint num2 = 0; num2 < engine.param.OBOB_EXPON - 1; num2++) { Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2), array3, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2 + 1), array4, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2 + 2), array5, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2 + 3), array6, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2 + 4), array8, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * num2 + 5), array9, 0, engine.param.NWORDS_FIELD); for (uint num3 = 0; num3 < t_points; num3++) { engine.fpx.fpmul_mont(Qj[num3].X[0], array3, array13[0]); engine.fpx.fpmul_mont(Qj[num3].X[1], array3, array13[1]); engine.fpx.fpmul_mont(Qj[num3].X[0], array4, array15[0]); engine.fpx.fpmul_mont(Qj[num3].X[1], array4, array15[1]); engine.fpx.fpaddPRIME(array10[num3][0], array8, array17[0]); engine.fpx.fpcopy(array10[num3][1], 0, array17[1]); engine.fpx.fpmul_mont(Qj[num3].X[0], array9, array18[0]); engine.fpx.fpmul_mont(Qj[num3].X[1], array9, array18[1]); engine.fpx.fp2sub(array13, Qj[num3].Y, array14); engine.fpx.fpaddPRIME(array14[0], array5, array14[0]); engine.fpx.fp2sub(array15, Qj[num3].Y, array16); engine.fpx.fpaddPRIME(array16[0], array6, array16[0]); engine.fpx.fp2mul_mont(array14, array16, array19); engine.fpx.fp2sub(array17, array18, array20); engine.fpx.fp2_conj(array20, array20); engine.fpx.fp2mul_mont(array19, array20, array19); engine.fpx.fp2sqr_mont(f[num3], array21); engine.fpx.fp2mul_mont(f[num3], array21, f[num3]); engine.fpx.fp2mul_mont(f[num3], array19, f[num3]); engine.fpx.fpsubPRIME(array13[1], Qj[num3].Y[0], array14[0]); engine.fpx.fpaddPRIME(array13[0], Qj[num3].Y[1], array14[1]); engine.fpx.fpnegPRIME(array14[1]); engine.fpx.fpaddPRIME(array14[1], array5, array14[1]); engine.fpx.fpsubPRIME(array15[1], Qj[num3].Y[0], array16[0]); engine.fpx.fpaddPRIME(array15[0], Qj[num3].Y[1], array16[1]); engine.fpx.fpnegPRIME(array16[1]); engine.fpx.fpaddPRIME(array16[1], array6, array16[1]); engine.fpx.fp2mul_mont(array14, array16, array19); engine.fpx.fp2add(array17, array18, array20); engine.fpx.fp2_conj(array20, array20); engine.fpx.fp2mul_mont(array19, array20, array19); engine.fpx.fp2sqr_mont(f[num3 + t_points], array21); engine.fpx.fp2mul_mont(f[num3 + t_points], array21, f[num3 + t_points]); engine.fpx.fp2mul_mont(f[num3 + t_points], array19, f[num3 + t_points]); } } for (uint num4 = 0; num4 < t_points; num4++) { Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * (engine.param.OBOB_EXPON - 1)), array, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * (engine.param.OBOB_EXPON - 1) + 1), array2, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * (engine.param.OBOB_EXPON - 1) + 2), array3, 0, engine.param.NWORDS_FIELD); Array.Copy(engine.param.T_tate3, engine.param.NWORDS_FIELD * (6 * (engine.param.OBOB_EXPON - 1) + 3), array7, 0, engine.param.NWORDS_FIELD); engine.fpx.fpsubPRIME(Qj[num4].X[0], array, array13[0]); engine.fpx.fpcopy(Qj[num4].X[1], 0, array13[1]); engine.fpx.fpmul_mont(array3, array13[0], array14[0]); engine.fpx.fpmul_mont(array3, array13[1], array14[1]); engine.fpx.fp2sub(array14, Qj[num4].Y, array15); engine.fpx.fpaddPRIME(array15[0], array2, array15[0]); engine.fpx.fp2mul_mont(array13, array15, array19); engine.fpx.fpsubPRIME(Qj[num4].X[0], array7, array20[0]); engine.fpx.fpcopy(Qj[num4].X[1], 0, array20[1]); engine.fpx.fpnegPRIME(array20[1]); engine.fpx.fp2mul_mont(array19, array20, array19); engine.fpx.fp2sqr_mont(f[num4], array21); engine.fpx.fp2mul_mont(f[num4], array21, f[num4]); engine.fpx.fp2mul_mont(f[num4], array19, f[num4]); engine.fpx.fpaddPRIME(Qj[num4].X[0], array, array13[0]); engine.fpx.fpmul_mont(array3, array13[0], array14[0]); engine.fpx.fpsubPRIME(Qj[num4].Y[0], array14[1], array15[0]); engine.fpx.fpaddPRIME(Qj[num4].Y[1], array14[0], array15[1]); engine.fpx.fpsubPRIME(array15[1], array2, array15[1]); engine.fpx.fp2mul_mont(array13, array15, array19); engine.fpx.fpaddPRIME(Qj[num4].X[0], array7, array20[0]); engine.fpx.fp2mul_mont(array19, array20, array19); engine.fpx.fp2sqr_mont(f[num4 + t_points], array21); engine.fpx.fp2mul_mont(f[num4 + t_points], array21, f[num4 + t_points]); engine.fpx.fp2mul_mont(f[num4 + t_points], array19, f[num4 + t_points]); } engine.fpx.mont_n_way_inv(f, 2 * t_points, array11); for (uint num5 = 0; num5 < 2 * t_points; num5++) { final_exponentiation_3_torsion(f[num5], array11[num5], f[num5]); } } private void final_exponentiation_3_torsion(ulong[][] f, ulong[][] finv, ulong[][] fout) { ulong[] array = new ulong[engine.param.NWORDS_FIELD]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array); engine.fpx.fp2_conj(f, array2); engine.fpx.fp2mul_mont(array2, finv, array2); for (uint num = 0; num < engine.param.OALICE_BITS; num++) { engine.fpx.sqr_Fp2_cycl(array2, array); } engine.fpx.fp2copy(array2, fout); } private void Tate2_pairings(PointProj P, PointProj Q, PointProjFull[] Qj, ulong[][][] f) { ulong[][][] array = SikeUtilities.InitArray(2 * t_points, 2, engine.param.NWORDS_FIELD); ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); ulong[][] array7 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array2[0]); for (uint num = 0; num < t_points; num++) { engine.fpx.fp2copy(array2, f[num]); engine.fpx.fp2copy(array2, f[num + t_points]); } ulong[][] x = P.X; ulong[][] z = P.Z; uint bOffset = 0; uint num2 = 1; ulong[] t_tate2_firststep_P = engine.param.T_tate2_firststep_P; ulong[] t_tate2_firststep_P2 = engine.param.T_tate2_firststep_P; engine.fpx.fpcopy(engine.param.T_tate2_firststep_P, 2 * engine.param.NWORDS_FIELD, array3[0]); engine.fpx.fpcopy(engine.param.T_tate2_firststep_P, 3 * engine.param.NWORDS_FIELD, array3[1]); for (uint num3 = 0; num3 < t_points; num3++) { engine.fpx.fp2sub(Qj[num3].X, x, array4); engine.fpx.fp2sub(Qj[num3].Y, z, array5); engine.fpx.fp2mul_mont(array3, array4, array4); engine.fpx.fp2sub(array4, array5, array6); engine.fpx.fpsubPRIME(Qj[num3].X[0], engine.param.T_tate2_firststep_P, bOffset, array7[0]); engine.fpx.fpcopy(Qj[num3].X[1], 0, array7[1]); engine.fpx.fpnegPRIME(array7[1]); engine.fpx.fp2mul_mont(array6, array7, array6); engine.fpx.fp2sqr_mont(f[num3], f[num3]); engine.fpx.fp2mul_mont(f[num3], array6, f[num3]); } uint num4 = 0; uint bOffset2 = engine.param.NWORDS_FIELD; ulong[] array8 = t_tate2_firststep_P; ulong[] b = t_tate2_firststep_P2; for (uint num5 = 0; num5 < engine.param.OALICE_BITS - 2; num5++) { t_tate2_firststep_P = engine.param.T_tate2_P; t_tate2_firststep_P2 = engine.param.T_tate2_P; ulong[] t_tate2_P = engine.param.T_tate2_P; bOffset = engine.param.NWORDS_FIELD * (3 * num5); num2 = engine.param.NWORDS_FIELD * (3 * num5 + 1); uint maOffset = engine.param.NWORDS_FIELD * (3 * num5 + 2); for (uint num6 = 0; num6 < t_points; num6++) { engine.fpx.fpsubPRIME(array8, num4, Qj[num6].X[0], array4[1]); engine.fpx.fpmul_mont(t_tate2_P, maOffset, array4[1], array4[1]); engine.fpx.fpmul_mont(t_tate2_P, maOffset, Qj[num6].X[1], array4[0]); engine.fpx.fpsubPRIME(Qj[num6].Y[1], b, bOffset2, array5[1]); engine.fpx.fpsubPRIME(array4[1], array5[1], array6[1]); engine.fpx.fpsubPRIME(array4[0], Qj[num6].Y[0], array6[0]); engine.fpx.fpsubPRIME(Qj[num6].X[0], t_tate2_firststep_P, bOffset, array7[0]); engine.fpx.fpcopy(Qj[num6].X[1], 0, array7[1]); engine.fpx.fpnegPRIME(array7[1]); engine.fpx.fp2mul_mont(array6, array7, array6); engine.fpx.fp2sqr_mont(f[num6], f[num6]); engine.fpx.fp2mul_mont(f[num6], array6, f[num6]); } array8 = t_tate2_firststep_P; b = t_tate2_firststep_P2; bOffset2 = num2; num4 = bOffset; } for (uint num7 = 0; num7 < t_points; num7++) { engine.fpx.fpsubPRIME(Qj[num7].X[0], array8, num4, array6[0]); engine.fpx.fpcopy(Qj[num7].X[1], 0, array6[1]); engine.fpx.fp2sqr_mont(f[num7], f[num7]); engine.fpx.fp2mul_mont(f[num7], array6, f[num7]); } x = Q.X; z = Q.Z; t_tate2_firststep_P = engine.param.T_tate2_firststep_Q; t_tate2_firststep_P2 = engine.param.T_tate2_firststep_Q; bOffset = 0; num2 = engine.param.NWORDS_FIELD; engine.fpx.fpcopy(engine.param.T_tate2_firststep_Q, 2 * engine.param.NWORDS_FIELD, array3[0]); engine.fpx.fpcopy(engine.param.T_tate2_firststep_Q, 3 * engine.param.NWORDS_FIELD, array3[1]); for (uint num8 = 0; num8 < t_points; num8++) { engine.fpx.fp2sub(Qj[num8].X, x, array4); engine.fpx.fp2sub(Qj[num8].Y, z, array5); engine.fpx.fp2mul_mont(array3, array4, array4); engine.fpx.fp2sub(array4, array5, array6); engine.fpx.fpsubPRIME(Qj[num8].X[0], t_tate2_firststep_P, bOffset, array7[0]); engine.fpx.fpcopy(Qj[num8].X[1], 0, array7[1]); engine.fpx.fpnegPRIME(array7[1]); engine.fpx.fp2mul_mont(array6, array7, array6); engine.fpx.fp2sqr_mont(f[num8 + t_points], f[num8 + t_points]); engine.fpx.fp2mul_mont(f[num8 + t_points], array6, f[num8 + t_points]); } array8 = t_tate2_firststep_P; b = t_tate2_firststep_P2; bOffset2 = num2; num4 = bOffset; for (uint num9 = 0; num9 < engine.param.OALICE_BITS - 2; num9++) { t_tate2_firststep_P = engine.param.T_tate2_Q; t_tate2_firststep_P2 = engine.param.T_tate2_Q; ulong[] t_tate2_P = engine.param.T_tate2_Q; bOffset = engine.param.NWORDS_FIELD * (3 * num9); num2 = engine.param.NWORDS_FIELD * (3 * num9 + 1); uint maOffset = engine.param.NWORDS_FIELD * (3 * num9 + 2); for (uint num10 = 0; num10 < t_points; num10++) { engine.fpx.fpsubPRIME(Qj[num10].X[0], array8, num4, array4[0]); engine.fpx.fpmul_mont(t_tate2_P, maOffset, array4[0], array4[0]); engine.fpx.fpmul_mont(t_tate2_P, maOffset, Qj[num10].X[1], array4[1]); engine.fpx.fpsubPRIME(Qj[num10].Y[0], b, bOffset2, array5[0]); engine.fpx.fpsubPRIME(array4[0], array5[0], array6[0]); engine.fpx.fpsubPRIME(array4[1], Qj[num10].Y[1], array6[1]); engine.fpx.fpsubPRIME(Qj[num10].X[0], t_tate2_firststep_P, bOffset, array7[0]); engine.fpx.fpcopy(Qj[num10].X[1], 0, array7[1]); engine.fpx.fpnegPRIME(array7[1]); engine.fpx.fp2mul_mont(array6, array7, array6); engine.fpx.fp2sqr_mont(f[num10 + t_points], f[num10 + t_points]); engine.fpx.fp2mul_mont(f[num10 + t_points], array6, f[num10 + t_points]); } array8 = t_tate2_firststep_P; b = t_tate2_firststep_P2; bOffset2 = num2; num4 = bOffset; } for (uint num11 = 0; num11 < t_points; num11++) { engine.fpx.fpsubPRIME(Qj[num11].X[0], array8, num4, array6[0]); engine.fpx.fpcopy(Qj[num11].X[1], 0, array6[1]); engine.fpx.fp2sqr_mont(f[num11 + t_points], f[num11 + t_points]); engine.fpx.fp2mul_mont(f[num11 + t_points], array6, f[num11 + t_points]); } engine.fpx.mont_n_way_inv(f, 2 * t_points, array); for (uint num12 = 0; num12 < 2 * t_points; num12++) { final_exponentiation_2_torsion(f[num12], array[num12], f[num12]); } } private void final_exponentiation_2_torsion(ulong[][] f, ulong[][] finv, ulong[][] fout) { ulong[] array = new ulong[engine.param.NWORDS_FIELD]; ulong[][] array2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD); engine.fpx.fpcopy(engine.param.Montgomery_one, 0, array); engine.fpx.fp2_conj(f, array2); engine.fpx.fp2mul_mont(array2, finv, array2); for (uint num = 0; num < engine.param.OBOB_EXPON; num++) { engine.fpx.cube_Fp2_cycl(array2, array); } engine.fpx.fp2copy(array2, fout); } } }