public static void secp256k1_ecmult_context_build(EcMultContext ctx, EventHandler <Callback> cb) { if (ctx.PreG != null) { return; } GeJ gj = new GeJ(); /* get the generator */ Group.secp256k1_gej_set_ge(gj, Group.Secp256K1GeConstG); #if USE_ENDOMORPHISM var WINDOW_G = 15; #else var WINDOW_G = 16; #endif var tblsize = (1 << ((WINDOW_G)-2)); ctx.PreG = new GeStorage[tblsize]; for (int i = 0; i < tblsize; i++) { ctx.PreG[i] = new GeStorage(); } /* precompute the tables with odd multiples */ secp256k1_ecmult_odd_multiples_table_storage_var(tblsize, ctx.PreG, gj, cb); #if USE_ENDOMORPHISM { secp256k1_gej g_128j; int i; ctx.pre_g_128 = (secp256k1_ge_storage(*)[])checked_malloc(cb, sizeof((*ctx.pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
public static void secp256k1_gej_set_ge(GeJ r, Ge a) { r.Infinity = a.Infinity; r.X = a.X.Clone(); r.Y = a.Y.Clone(); Field.SetInt(r.Z, 1U); }
public static void ContextBuild(EcmultGenContext ctx, EventHandler <Callback> cb) { Ge[] r1 = new Ge[1024]; GeJ r2 = new GeJ(); GeJ geJ1 = new GeJ(); if (ctx.Prec != null) { return; } ctx.PrecInit(); Group.secp256k1_gej_set_ge(r2, Group.Secp256K1GeConstG); byte[] bytes = Encoding.UTF8.GetBytes("The scalar for this x is unknown"); Fe fe = new Fe(); Ge ge = new Ge(); Field.SetB32(fe, bytes); Group.secp256k1_ge_set_xo_var(ge, fe, false); Group.secp256k1_gej_set_ge(geJ1, ge); Group.secp256k1_gej_add_ge_var(geJ1, geJ1, Group.Secp256K1GeConstG, (Fe)null); GeJ[] a = new GeJ[1024]; for (int index = 0; index < a.Length; ++index) { a[index] = new GeJ(); } GeJ geJ2 = r2.Clone(); GeJ geJ3 = geJ1.Clone(); for (int index1 = 0; index1 < 64; ++index1) { a[index1 * 16] = geJ3.Clone(); for (int index2 = 1; index2 < 16; ++index2) { Group.secp256k1_gej_add_var(a[index1 * 16 + index2], a[index1 * 16 + index2 - 1], geJ2, (Fe)null); } for (int index2 = 0; index2 < 4; ++index2) { Group.secp256k1_gej_double_var(geJ2, geJ2, (Fe)null); } Group.secp256k1_gej_double_var(geJ3, geJ3, (Fe)null); if (index1 == 62) { Group.secp256k1_gej_neg(geJ3, geJ3); Group.secp256k1_gej_add_var(geJ3, geJ3, geJ1, (Fe)null); } } for (int index = 0; index < r1.Length; ++index) { r1[index] = new Ge(); } Group.secp256k1_ge_set_all_gej_var(r1, a, 1024, cb); for (int index1 = 0; index1 < 64; ++index1) { for (int index2 = 0; index2 < 16; ++index2) { Group.ToStorage(ctx.Prec[index1][index2], r1[index1 * 16 + index2]); } } EcMultGen.Blind(ctx, (byte[])null); }
public static void secp256k1_gej_clear(GeJ r) { r.Infinity = false; Field.Clear(r.X); Field.Clear(r.Y); Field.Clear(r.Z); }
public static void secp256k1_gej_neg(GeJ r, GeJ a) { r.Infinity = a.Infinity; r.X = a.X.Clone(); r.Y = a.Y.Clone(); r.Z = a.Z.Clone(); Field.NormalizeWeak(r.Y); Field.Negate(r.Y, r.Y, 1U); }
public static void secp256k1_gej_rescale(GeJ r, Fe s) { Fe fe = new Fe(); Field.Sqr(fe, s); Field.Mul(r.X, r.X, fe); Field.Mul(r.Y, r.Y, fe); Field.Mul(r.Y, r.Y, s); Field.Mul(r.Z, r.Z, s); }
public static void secp256k1_ge_set_gej_zinv(Ge r, GeJ a, Fe zi) { Fe fe1 = new Fe(); Fe fe2 = new Fe(); Field.Sqr(fe1, zi); Field.Mul(fe2, fe1, zi); Field.Mul(r.X, a.X, fe1); Field.Mul(r.Y, a.Y, fe2); r.Infinity = a.Infinity; }
public static void SetGeJ(Ge r, GeJ a) { Fe fe1 = new Fe(); Fe fe2 = new Fe(); r.Infinity = a.Infinity; Field.Inv(a.Z, a.Z); Field.Sqr(fe1, a.Z); Field.Mul(fe2, a.Z, fe1); Field.Mul(a.X, a.X, fe1); Field.Mul(a.Y, a.Y, fe2); Field.SetInt(a.Z, 1U); r.X = a.X.Clone(); r.Y = a.Y.Clone(); }
public static bool EcPubKeyCreate(Context ctx, PubKey pubkey, byte[] seckey) { GeJ r = new GeJ(); Ge ge = new Ge(); Scalar scalar = new Scalar(); int num = !Scalar.SetB32(scalar, seckey) & !Scalar.IsZero(scalar) ? 1 : 0; if (num != 0) { EcMultGen.secp256k1_ecmult_gen(ctx.EcMultGenCtx, out r, scalar); Group.SetGeJ(ge, r); Secp256K1T.SavePubKey(pubkey, ge); } Scalar.Clear(scalar); return(num != 0); }
public static void secp256k1_gej_double_var(GeJ r, GeJ a, Fe rzr) { r.Infinity = a.Infinity; if (r.Infinity) { if (rzr == null) { return; } Field.SetInt(rzr, 1U); } else { if (rzr != null) { rzr = a.Y.Clone(); Field.NormalizeWeak(rzr); Field.MulInt(rzr, 2U); } Field.Mul(r.Z, a.Z, a.Y); Field.MulInt(r.Z, 2U); Fe fe1 = new Fe(); Field.Sqr(fe1, a.X); Field.MulInt(fe1, 3U); Fe fe2 = new Fe(); Field.Sqr(fe2, fe1); Fe fe3 = new Fe(); Field.Sqr(fe3, a.Y); Field.MulInt(fe3, 2U); Fe fe4 = new Fe(); Field.Sqr(fe4, fe3); Field.MulInt(fe4, 2U); Field.Mul(fe3, fe3, a.X); r.X = fe3.Clone(); Field.MulInt(r.X, 4U); Field.Negate(r.X, r.X, 4U); Field.Add(r.X, fe2); Field.Negate(fe2, fe2, 1U); Field.MulInt(fe3, 6U); Field.Add(fe3, fe2); Field.Mul(r.Y, fe1, fe3); Field.Negate(fe2, fe4, 2U); Field.Add(r.Y, fe2); } }
public static bool EcPubKeyCreate(Context ctx, PubKey pubkey, byte[] seckey) { GeJ pj = new GeJ(); Ge p = new Ge(); var sec = new Scalar(); var overflow = Scalar.SetB32(sec, seckey); var ret = !overflow & !Scalar.IsZero(sec); if (ret) { EcMultGen.secp256k1_ecmult_gen(ctx.EcMultGenCtx, out pj, sec); Group.SetGeJ(p, pj); SavePubKey(pubkey, p); } Scalar.Clear(sec); return(ret); }
public static void secp256k1_ecmult_context_build(EcMultContext ctx, EventHandler <Callback> cb) { if (ctx.PreG != null) { return; } GeJ geJ = new GeJ(); Group.secp256k1_gej_set_ge(geJ, Group.Secp256K1GeConstG); int n = 1 << 16 - 2; ctx.PreG = new GeStorage[n]; for (int index = 0; index < n; ++index) { ctx.PreG[index] = new GeStorage(); } EcMult.secp256k1_ecmult_odd_multiples_table_storage_var(n, ctx.PreG, geJ, cb); }
public static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, GeStorage[] pre, GeJ a, EventHandler <Callback> cb) { GeJ[] geJArray = new GeJ[n]; Ge[] r = new Ge[n]; Fe[] zr = new Fe[n]; for (int index = 0; index < n; ++index) { geJArray[index] = new GeJ(); r[index] = new Ge(); zr[index] = new Fe(); } EcMult.secp256k1_ecmult_odd_multiples_table(n, geJArray, zr, a); Group.secp256k1_ge_set_table_gej_var(r, geJArray, zr, n); for (int index = 0; index < n; ++index) { Group.ToStorage(pre[index], r[index]); } }
///** Fill a table 'pre' with precomputed odd multiples of a. // * // * There are two versions of this function: // * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its // * resulting point set to a single constant Z denominator, stores the X and Y // * coordinates as ge_storage points in pre, and stores the global Z in rz. // * It only operates on tables sized for WINDOW_A wnaf multiples. // * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its // * resulting point set to actually affine points, and stores those in pre. // * It operates on tables of any size, but uses heap-allocated temporaries. // * // * To compute a*P + b*G, we compute a table for P using the first function, // * and for G using the second (which requires an inverse, but it only needs to // * happen once). // */ //static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge* pre, secp256k1_fe* globalz, const secp256k1_gej* a) //{ // secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; // secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; // /* Compute the odd multiples in Jacobian form. */ // secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); // /* Bring them to the same Z denominator. */ // secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); //} public static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, GeStorage[] pre, GeJ a, EventHandler <Callback> cb) { GeJ[] prej = new GeJ[n]; Ge[] prea = new Ge[n]; Fe[] zr = new Fe[n]; for (int i = 0; i < n; i++) { prej[i] = new GeJ(); prea[i] = new Ge(); zr[i] = new Fe(); } /* Compute the odd multiples in Jacobian form. */ secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); /* Convert them in batch to affine coordinates. */ Group.secp256k1_ge_set_table_gej_var(prea, prej, zr, n); /* Convert them to compact storage form. */ for (var i = 0; i < n; i++) { Group.ToStorage(pre[i], prea[i]); } }
// // /** Double multiply: R = na*A + ng*G */ // // static void secp256k1_ecmult(const secp256k1_ecmult_context* ctx, secp256k1_gej* r, const secp256k1_gej* a, const secp256k1_scalar* na, const secp256k1_scalar* ng); //#if defined(EXHAUSTIVE_TEST_ORDER) ///* We need to lower these values for exhaustive tests because // * the tables cannot have infinities in them (this breaks the // * affine-isomorphism stuff which tracks z-ratios) */ //#if EXHAUSTIVE_TEST_ORDER > 128 //#define WINDOW_A 5 //#define WINDOW_G 8 //#elif EXHAUSTIVE_TEST_ORDER > 8 //#define WINDOW_A 4 //#define WINDOW_G 4 //#else //#define WINDOW_A 2 //#define WINDOW_G 2 //#endif //#else // /* optimal for 128-bit and 256-bit exponents. */ //#define WINDOW_A 5 // /** larger numbers may result in slightly better performance, at the cost of // exponentially larger precomputed tables. */ //# ifdef USE_ENDOMORPHISM // /** Two tables for window size 15: 1.375 MiB. */ //#define WINDOW_G 15 //#else // /** One table for window size 16: 1.375 MiB. */ //#define WINDOW_G 16 //#endif //#endif /** The number of entries a table with precomputed multiples needs to have. */ //#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) /// <summary> /// Fill a table 'prej' with precomputed odd multiples of a. Prej will contain /// the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will /// contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. /// Prej's Z values are undefined, except for the last value. /// </summary> /// <param name="n"></param> /// <param name="prej"></param> /// <param name="zr"></param> /// <param name="a"></param> static void secp256k1_ecmult_odd_multiples_table(int n, GeJ[] prej, Fe[] zr, GeJ a) { Debug.Assert(!a.Infinity); GeJ d = new GeJ(); Group.secp256k1_gej_double_var(d, a, null); /* * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. */ Ge dGe = new Ge(); dGe.X = d.X.Clone(); dGe.Y = d.Y.Clone(); dGe.Infinity = false; Ge aGe = new Ge(); Group.secp256k1_ge_set_gej_zinv(aGe, a, d.Z); prej[0].X = aGe.X.Clone(); prej[0].Y = aGe.Y.Clone(); prej[0].Z = a.Z.Clone(); prej[0].Infinity = false; zr[0] = d.Z.Clone(); for (var i = 1; i < n; i++) { Group.secp256k1_gej_add_ge_var(prej[i], prej[i - 1], dGe, zr[i]); } /* * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only * the final point's z coordinate is actually used though, so just update that. */ Field.Mul(prej[n - 1].Z, prej[n - 1].Z, d.Z); }
public static void secp256k1_ecmult_gen(EcmultGenContext ctx, out GeJ r, Scalar gn) { Ge ge = new Ge(); GeStorage geStorage = new GeStorage(); r = ctx.Initial.Clone(); Scalar r1 = new Scalar(); Scalar.Add(r1, gn, ctx.Blind); ge.Infinity = false; for (int index1 = 0; index1 < 64; ++index1) { uint bits = r1.GetBits(index1 * 4, 4); for (int index2 = 0; index2 < 16; ++index2) { Group.StorageCmov(geStorage, ctx.Prec[index1][index2], (long)index2 == (long)bits); } Group.FromStorage(ge, geStorage); Group.GeJAddGe(r, r, ge); } Group.secp256k1_ge_clear(ge); Scalar.Clear(r1); }
private static void secp256k1_ecmult_odd_multiples_table(int n, GeJ[] prej, Fe[] zr, GeJ a) { GeJ r1 = new GeJ(); Group.secp256k1_gej_double_var(r1, a, (Fe)null); Ge b = new Ge(); b.X = r1.X.Clone(); b.Y = r1.Y.Clone(); b.Infinity = false; Ge r2 = new Ge(); Group.secp256k1_ge_set_gej_zinv(r2, a, r1.Z); prej[0].X = r2.X.Clone(); prej[0].Y = r2.Y.Clone(); prej[0].Z = a.Z.Clone(); prej[0].Infinity = false; zr[0] = r1.Z.Clone(); for (int index = 1; index < n; ++index) { Group.secp256k1_gej_add_ge_var(prej[index], prej[index - 1], b, zr[index]); } Field.Mul(prej[n - 1].Z, prej[n - 1].Z, r1.Z); }
///** Check whether a group element is valid (i.e., on the curve). */ // static int secp256k1_ge_is_valid_var(const secp256k1_ge* a); // static void secp256k1_ge_neg(secp256k1_ge* r, const secp256k1_ge* a); ///** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to // * the same global z "denominator". zr must contain the known z-ratios such // * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y // * coordinates of the result are stored in r, the common z coordinate is // * stored in globalz. */ // static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge* r, secp256k1_fe* globalz, const secp256k1_gej* a, const secp256k1_fe* zr); ///** Set a group element (jacobian) equal to the point at infinity. */ // static void secp256k1_gej_set_infinity(secp256k1_gej* r); ///** Compare the X coordinate of a group element (jacobian). */ // static int secp256k1_gej_eq_x_var(const secp256k1_fe* x, const secp256k1_gej* a); ///** Check whether a group element is the point at infinity. */ // static int secp256k1_gej_is_infinity(const secp256k1_gej* a); ///** Check whether a group element's y coordinate is a quadratic residue. */ // static int secp256k1_gej_has_quad_y_var(const secp256k1_gej* a); ///** Set r equal to the double of a. If rzr is not-null, r.z = a.z * *rzr (where infinity means an implicit z = 0). // * a may not be zero. Constant time. */ // static void secp256k1_gej_double_nonzero(secp256k1_gej* r, const secp256k1_gej* a, secp256k1_fe* rzr); /// <summary> /// Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). /// </summary> /// <param name="r"></param> /// <param name="a"></param> /// <param name="b"></param> public static void GeJAddGe(GeJ r, GeJ a, Ge b) {
public static void secp256k1_gej_add_ge_var(GeJ r, GeJ a, Ge b, Fe rzr) { if (a.Infinity) { Group.secp256k1_gej_set_ge(r, b); } else if (b.Infinity) { if (rzr != null) { Field.SetInt(rzr, 1U); } r = a.Clone(); } else { r.Infinity = false; Fe fe1 = new Fe(); Field.Sqr(fe1, a.Z); Fe fe2 = a.X.Clone(); Field.NormalizeWeak(fe2); Fe fe3 = new Fe(); Field.Mul(fe3, b.X, fe1); Fe fe4 = a.Y.Clone(); Field.NormalizeWeak(fe4); Fe fe5 = new Fe(); Field.Mul(fe5, b.Y, fe1); Field.Mul(fe5, fe5, a.Z); Fe fe6 = new Fe(); Field.Negate(fe6, fe2, 1U); Field.Add(fe6, fe3); Fe fe7 = new Fe(); Field.Negate(fe7, fe4, 1U); Field.Add(fe7, fe5); if (Field.NormalizesToZeroVar(fe6)) { if (Field.NormalizesToZeroVar(fe7)) { Group.secp256k1_gej_double_var(r, a, rzr); } else { if (rzr != null) { Field.SetInt(rzr, 0U); } r.Infinity = true; } } else { Fe fe8 = new Fe(); Field.Sqr(fe8, fe7); Fe fe9 = new Fe(); Field.Sqr(fe9, fe6); Fe fe10 = new Fe(); Field.Mul(fe10, fe6, fe9); if (rzr != null) { rzr = fe6.Clone(); } Field.Mul(r.Z, a.Z, fe6); Fe fe11 = new Fe(); Field.Mul(fe11, fe2, fe9); r.X = fe11.Clone(); Field.MulInt(r.X, 2U); Field.Add(r.X, fe10); Field.Negate(r.X, r.X, 3U); Field.Add(r.X, fe8); Field.Negate(r.Y, r.X, 5U); Field.Add(r.Y, fe11); Field.Mul(r.Y, r.Y, fe7); Field.Mul(fe10, fe10, fe4); Field.Negate(fe10, fe10, 1U); Field.Add(r.Y, fe10); } } }
public static void GeJAddGe(GeJ r, GeJ a, Ge b) { uint[] arr = new uint[10]; arr[0] = 1U; Fe a1 = new Fe(arr); if (b.Infinity) { throw new ArithmeticException(); } Fe fe1 = new Fe(); Field.Sqr(fe1, a.Z); Fe fe2 = a.X.Clone(); Field.NormalizeWeak(fe2); Fe fe3 = new Fe(); Field.Mul(fe3, b.X, fe1); Fe r1 = a.Y.Clone(); Field.NormalizeWeak(r1); Fe fe4 = new Fe(); Field.Mul(fe4, b.Y, fe1); Field.Mul(fe4, fe4, a.Z); Fe fe5 = fe2.Clone(); Field.Add(fe5, fe3); Fe fe6 = r1.Clone(); Field.Add(fe6, fe4); Fe fe7 = new Fe(); Field.Sqr(fe7, fe5); Fe fe8 = new Fe(); Field.Negate(fe8, fe3, 1U); Fe fe9 = new Fe(); Field.Mul(fe9, fe2, fe8); Field.Add(fe7, fe9); bool flag1 = Field.NormalizesToZero(fe6) && Field.NormalizesToZero(fe7); Fe fe10 = r1.Clone(); Field.MulInt(fe10, 2U); Field.Add(fe8, fe2); Field.Cmov(fe10, fe7, !flag1); Field.Cmov(fe8, fe6, !flag1); Fe fe11 = new Fe(); Field.Sqr(fe11, fe8); Fe fe12 = new Fe(); Field.Mul(fe12, fe11, fe5); Field.Sqr(fe11, fe11); Field.Cmov(fe11, fe6, flag1); Field.Sqr(fe5, fe10); Field.Mul(r.Z, a.Z, fe8); bool flag2 = !a.Infinity && Field.NormalizesToZero(r.Z); Field.MulInt(r.Z, 2U); Field.Negate(fe12, fe12, 1U); Field.Add(fe5, fe12); Field.NormalizeWeak(fe5); r.X = fe5.Clone(); Field.MulInt(fe5, 2U); Field.Add(fe5, fe12); Field.Mul(fe5, fe5, fe10); Field.Add(fe5, fe11); Field.Negate(r.Y, fe5, 3U); Field.NormalizeWeak(r.Y); Field.MulInt(r.X, 4U); Field.MulInt(r.Y, 4U); Field.Cmov(r.X, b.X, a.Infinity); Field.Cmov(r.Y, b.Y, a.Infinity); Field.Cmov(r.Z, a1, a.Infinity); r.Infinity = flag2; }
public static void ContextBuild(EcmultGenContext ctx, EventHandler <Callback> cb) { #if !USE_ECMULT_STATIC_PRECOMPUTATION Ge[] prec = new Ge[1024]; GeJ gj = new GeJ(); GeJ numsGej = new GeJ(); int i, j; #endif if (ctx.Prec != null) { return; } #if !USE_ECMULT_STATIC_PRECOMPUTATION ctx.PrecInit(); /* get the generator */ Group.secp256k1_gej_set_ge(gj, Group.Secp256K1GeConstG); /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ { var numsB32 = Encoding.UTF8.GetBytes("The scalar for this x is unknown"); Fe numsX = new Fe(); Ge numsGe = new Ge(); var r = Field.SetB32(numsX, numsB32); //(void)r; Util.VERIFY_CHECK(r); r = Group.secp256k1_ge_set_xo_var(numsGe, numsX, false); //(void)r; Util.VERIFY_CHECK(r); Group.secp256k1_gej_set_ge(numsGej, numsGe); /* Add G to make the bits in x uniformly distributed. */ Group.secp256k1_gej_add_ge_var(numsGej, numsGej, Group.Secp256K1GeConstG, null); } /* compute prec. */ { GeJ[] precj = new GeJ[1024]; /* Jacobian versions of prec. */ for (int k = 0; k < precj.Length; k++) { precj[k] = new GeJ(); } GeJ gbase; GeJ numsbase; gbase = gj.Clone(); /* 16^j * G */ numsbase = numsGej.Clone(); /* 2^j * nums. */ for (j = 0; j < 64; j++) { /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ precj[j * 16] = numsbase.Clone(); for (i = 1; i < 16; i++) { Group.secp256k1_gej_add_var(precj[j * 16 + i], precj[j * 16 + i - 1], gbase, null); } /* Multiply gbase by 16. */ for (i = 0; i < 4; i++) { Group.secp256k1_gej_double_var(gbase, gbase, null); } /* Multiply numbase by 2. */ Group.secp256k1_gej_double_var(numsbase, numsbase, null); if (j == 62) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ Group.secp256k1_gej_neg(numsbase, numsbase); Group.secp256k1_gej_add_var(numsbase, numsbase, numsGej, null); } } for (int k = 0; k < prec.Length; k++) { prec[k] = new Ge(); } Group.secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { Group.ToStorage(ctx.Prec[j][i], prec[j * 16 + i]); } } #else (void)cb; ctx.prec = (secp256k1_ge_storage(*)[64][16])secp256k1_ecmult_static_context;