Ed448
A low-level implementation of the Ed448 and Ed448ph instantiations of the Edwards-Curve Digital Signature
Algorithm specified in RFC 8032.
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Math.EC.Rfc7748;
using Org.BouncyCastle.Math.Raw;
using Org.BouncyCastle.Security;
using System;
namespace Org.BouncyCastle.Math.EC.Rfc8032
{
public static class Ed448
{
public enum Algorithm
{
Ed448,
Ed448ph
}
public sealed class PublicPoint
{
internal readonly uint[] m_data;
internal PublicPoint(uint[] data)
{
m_data = data;
}
}
private struct PointAffine
{
internal uint[] x;
internal uint[] y;
}
private struct PointProjective
{
internal uint[] x;
internal uint[] y;
internal uint[] z;
}
private struct PointTemp
{
internal uint[] r0;
internal uint[] r1;
internal uint[] r2;
internal uint[] r3;
internal uint[] r4;
internal uint[] r5;
internal uint[] r6;
internal uint[] r7;
}
private const int CoordUints = 14;
private const int PointBytes = 57;
private const int ScalarUints = 14;
private const int ScalarBytes = 57;
public static readonly int PrehashSize = 64;
public static readonly int PublicKeySize = 57;
public static readonly int SecretKeySize = 57;
public static readonly int SignatureSize = 114;
private static readonly byte[] Dom4Prefix = new byte[8] {
83,
105,
103,
69,
100,
52,
52,
56
};
private static readonly uint[] P = new uint[14] {
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
4294967294,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue
};
private static readonly uint[] B_x = new uint[16] {
118276190,
40534716,
9670182,
135141552,
85017403,
259173222,
68333082,
171784774,
174973732,
15824510,
73756743,
57518561,
94773951,
248652241,
107736333,
82941708
};
private static readonly uint[] B_y = new uint[16] {
36764180,
8885695,
130592152,
20104429,
163904957,
30304195,
121295871,
5901357,
125344798,
171541512,
175338348,
209069246,
3626697,
38307682,
24032956,
110359655
};
private static readonly uint[] B225_x = new uint[16] {
110141154,
30892124,
160820362,
264558960,
217232225,
47722141,
19029845,
8326902,
183409749,
170134547,
90340180,
222600478,
61097333,
7431335,
198491505,
102372861
};
private static readonly uint[] B225_y = new uint[16] {
221945828,
50763449,
132637478,
109250759,
216053960,
61612587,
50649998,
138339097,
98949899,
248139835,
186410297,
126520782,
47339196,
78164062,
198835543,
169622712
};
private const uint C_d = 39081;
private const int WnafWidth225 = 5;
private const int WnafWidthBase = 7;
private const int PrecompBlocks = 5;
private const int PrecompTeeth = 5;
private const int PrecompSpacing = 18;
private const int PrecompRange = 450;
private const int PrecompPoints = 16;
private const int PrecompMask = 15;
private static readonly object PrecompLock = new object();
private static PointAffine[] PrecompBaseWnaf = null;
private static PointAffine[] PrecompBase225Wnaf = null;
private static uint[] PrecompBaseComb = null;
private static byte[] CalculateS(byte[] r, byte[] k, byte[] s)
{
uint[] array = new uint[28];
Scalar448.Decode(r, array);
uint[] array2 = new uint[14];
Scalar448.Decode(k, array2);
uint[] array3 = new uint[14];
Scalar448.Decode(s, array3);
Nat.MulAddTo(14, array2, array3, array);
byte[] array4 = new byte[114];
Codec.Encode32(array, 0, array.Length, array4, 0);
return Scalar448.Reduce912(array4);
}
private static bool CheckContextVar(byte[] ctx)
{
if (ctx != null)
return ctx.Length < 256;
return false;
}
private static int CheckPoint(ref PointAffine p)
{
uint[] array = X448Field.Create();
uint[] array2 = X448Field.Create();
uint[] array3 = X448Field.Create();
X448Field.Sqr(p.x, array2);
X448Field.Sqr(p.y, array3);
X448Field.Mul(array2, array3, array);
X448Field.Add(array2, array3, array2);
X448Field.Mul(array, 39081, array);
X448Field.SubOne(array);
X448Field.Add(array, array2, array);
X448Field.Normalize(array);
X448Field.Normalize(array3);
return X448Field.IsZero(array) & ~X448Field.IsZero(array3);
}
private static int CheckPoint(PointProjective p)
{
uint[] array = X448Field.Create();
uint[] array2 = X448Field.Create();
uint[] array3 = X448Field.Create();
uint[] array4 = X448Field.Create();
X448Field.Sqr(p.x, array2);
X448Field.Sqr(p.y, array3);
X448Field.Sqr(p.z, array4);
X448Field.Mul(array2, array3, array);
X448Field.Add(array2, array3, array2);
X448Field.Mul(array2, array4, array2);
X448Field.Sqr(array4, array4);
X448Field.Mul(array, 39081, array);
X448Field.Sub(array, array4, array);
X448Field.Add(array, array2, array);
X448Field.Normalize(array);
X448Field.Normalize(array3);
X448Field.Normalize(array4);
return X448Field.IsZero(array) & ~X448Field.IsZero(array3) & ~X448Field.IsZero(array4);
}
private static bool CheckPointFullVar(byte[] p)
{
if ((p[56] & 127) != 0)
return false;
uint num;
uint num2 = (num = Codec.Decode32(p, 52)) ^ P[13];
for (int num3 = 12; num3 > 0; num3--) {
uint num4 = Codec.Decode32(p, num3 * 4);
if (num2 == 0 && num4 > P[num3])
return false;
num |= num4;
num2 |= (num4 ^ P[num3]);
}
uint num5 = Codec.Decode32(p, 0);
if (num == 0 && num5 <= 1)
return false;
if (num2 == 0 && num5 >= P[0] - 1)
return false;
return true;
}
private static bool CheckPointOrderVar(ref PointAffine p)
{
Init(out PointProjective r);
ScalarMultOrderVar(ref p, ref r);
return NormalizeToNeutralElementVar(ref r);
}
private static bool CheckPointVar(byte[] p)
{
if ((p[56] & 127) != 0)
return false;
if (Codec.Decode32(p, 52) < P[13])
return true;
int num = (p[28] == 255) ? 7 : 0;
for (int num2 = 12; num2 >= num; num2--) {
if (Codec.Decode32(p, num2 * 4) < P[num2])
return true;
}
return false;
}
private static byte[] Copy(byte[] buf, int off, int len)
{
byte[] array = new byte[len];
Array.Copy(buf, off, array, 0, len);
return array;
}
public static IXof CreatePrehash()
{
return CreateXof();
}
private static IXof CreateXof()
{
return new ShakeDigest(256);
}
private static bool DecodePointVar(byte[] p, bool negate, ref PointAffine r)
{
int num = (p[56] & 128) >> 7;
X448Field.Decode(p, r.y);
uint[] array = X448Field.Create();
uint[] array2 = X448Field.Create();
X448Field.Sqr(r.y, array);
X448Field.Mul(array, 39081, array2);
X448Field.Negate(array, array);
X448Field.AddOne(array);
X448Field.AddOne(array2);
if (!X448Field.SqrtRatioVar(array, array2, r.x))
return false;
X448Field.Normalize(r.x);
if (num == 1 && X448Field.IsZeroVar(r.x))
return false;
if (negate ^ (num != (r.x[0] & 1))) {
X448Field.Negate(r.x, r.x);
X448Field.Normalize(r.x);
}
return true;
}
private static void Dom4(IXof d, byte phflag, byte[] ctx)
{
int num = Dom4Prefix.Length;
byte[] array = new byte[num + 2 + ctx.Length];
Dom4Prefix.CopyTo(array, 0);
array[num] = phflag;
array[num + 1] = (byte)ctx.Length;
ctx.CopyTo(array, num + 2);
d.BlockUpdate(array, 0, array.Length);
}
private static void EncodePoint(ref PointAffine p, byte[] r, int rOff)
{
X448Field.Encode(p.y, r, rOff);
r[rOff + 57 - 1] = (byte)((p.x[0] & 1) << 7);
}
public static void EncodePublicPoint(PublicPoint publicPoint, byte[] pk, int pkOff)
{
X448Field.Encode(publicPoint.m_data, 16, pk, pkOff);
pk[pkOff + 57 - 1] = (byte)((publicPoint.m_data[0] & 1) << 7);
}
private static int EncodeResult(ref PointProjective p, byte[] r, int rOff)
{
Init(out PointAffine r2);
NormalizeToAffine(ref p, ref r2);
int result = CheckPoint(ref r2);
EncodePoint(ref r2, r, rOff);
return result;
}
private static PublicPoint ExportPoint(ref PointAffine p)
{
uint[] array = new uint[32];
X448Field.Copy(p.x, 0, array, 0);
X448Field.Copy(p.y, 0, array, 16);
return new PublicPoint(array);
}
public static void GeneratePrivateKey(SecureRandom random, byte[] k)
{
if (k.Length != SecretKeySize)
throw new ArgumentException("k");
random.NextBytes(k);
}
public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)
{
IXof xof = CreateXof();
byte[] array = new byte[114];
xof.BlockUpdate(sk, skOff, SecretKeySize);
xof.OutputFinal(array, 0, array.Length);
byte[] array2 = new byte[57];
PruneScalar(array, 0, array2);
ScalarMultBaseEncoded(array2, pk, pkOff);
}
public static PublicPoint GeneratePublicKey(byte[] sk, int skOff)
{
IXof xof = CreateXof();
byte[] array = new byte[114];
xof.BlockUpdate(sk, skOff, SecretKeySize);
xof.OutputFinal(array, 0, array.Length);
byte[] array2 = new byte[57];
PruneScalar(array, 0, array2);
Init(out PointProjective r);
ScalarMultBase(array2, ref r);
Init(out PointAffine r2);
NormalizeToAffine(ref r, ref r2);
if (CheckPoint(ref r2) == 0)
throw new InvalidOperationException();
return ExportPoint(ref r2);
}
private static uint GetWindow4(uint[] x, int n)
{
int num = (int)((uint)n >> 3);
int num2 = (n & 7) << 2;
return (x[num] >> num2) & 15;
}
private static void ImplSign(IXof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
Dom4(d, phflag, ctx);
d.BlockUpdate(h, 57, 57);
d.BlockUpdate(m, mOff, mLen);
d.OutputFinal(h, 0, h.Length);
byte[] array = Scalar448.Reduce912(h);
byte[] array2 = new byte[57];
ScalarMultBaseEncoded(array, array2, 0);
Dom4(d, phflag, ctx);
d.BlockUpdate(array2, 0, 57);
d.BlockUpdate(pk, pkOff, 57);
d.BlockUpdate(m, mOff, mLen);
d.OutputFinal(h, 0, h.Length);
byte[] k = Scalar448.Reduce912(h);
byte[] sourceArray = CalculateS(array, k, s);
Array.Copy(array2, 0, sig, sigOff, 57);
Array.Copy(sourceArray, 0, sig, sigOff + 57, 57);
}
private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
if (!CheckContextVar(ctx))
throw new ArgumentException("ctx");
IXof xof = CreateXof();
byte[] array = new byte[114];
xof.BlockUpdate(sk, skOff, SecretKeySize);
xof.OutputFinal(array, 0, array.Length);
byte[] array2 = new byte[57];
PruneScalar(array, 0, array2);
byte[] array3 = new byte[57];
ScalarMultBaseEncoded(array2, array3, 0);
ImplSign(xof, array, array2, array3, 0, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
if (!CheckContextVar(ctx))
throw new ArgumentException("ctx");
IXof xof = CreateXof();
byte[] array = new byte[114];
xof.BlockUpdate(sk, skOff, SecretKeySize);
xof.OutputFinal(array, 0, array.Length);
byte[] array2 = new byte[57];
PruneScalar(array, 0, array2);
ImplSign(xof, array, array2, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen)
{
if (!CheckContextVar(ctx))
throw new ArgumentException("ctx");
byte[] array = Copy(sig, sigOff, 57);
byte[] s = Copy(sig, sigOff + 57, 57);
byte[] array2 = Copy(pk, pkOff, PublicKeySize);
if (!CheckPointVar(array))
return false;
uint[] array3 = new uint[14];
if (!Scalar448.CheckVar(s, array3))
return false;
if (!CheckPointFullVar(array2))
return false;
Init(out PointAffine r);
if (!DecodePointVar(array, true, ref r))
return false;
Init(out PointAffine r2);
if (!DecodePointVar(array2, true, ref r2))
return false;
IXof xof = CreateXof();
byte[] array4 = new byte[114];
Dom4(xof, phflag, ctx);
xof.BlockUpdate(array, 0, 57);
xof.BlockUpdate(array2, 0, 57);
xof.BlockUpdate(m, mOff, mLen);
xof.OutputFinal(array4, 0, array4.Length);
byte[] k = Scalar448.Reduce912(array4);
uint[] array5 = new uint[14];
Scalar448.Decode(k, array5);
uint[] array6 = new uint[8];
uint[] array7 = new uint[8];
if (!Scalar448.ReduceBasisVar(array5, array6, array7))
throw new InvalidOperationException();
Scalar448.Multiply225Var(array3, array7, array3);
Init(out PointProjective r3);
ScalarMultStraus225Var(array3, array6, ref r2, array7, ref r, ref r3);
return NormalizeToNeutralElementVar(ref r3);
}
private static bool ImplVerify(byte[] sig, int sigOff, PublicPoint publicPoint, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen)
{
if (!CheckContextVar(ctx))
throw new ArgumentException("ctx");
byte[] array = Copy(sig, sigOff, 57);
byte[] s = Copy(sig, sigOff + 57, 57);
if (!CheckPointVar(array))
return false;
uint[] array2 = new uint[14];
if (!Scalar448.CheckVar(s, array2))
return false;
Init(out PointAffine r);
if (!DecodePointVar(array, true, ref r))
return false;
Init(out PointAffine r2);
X448Field.Negate(publicPoint.m_data, r2.x);
X448Field.Copy(publicPoint.m_data, 16, r2.y, 0);
byte[] array3 = new byte[PublicKeySize];
EncodePublicPoint(publicPoint, array3, 0);
IXof xof = CreateXof();
byte[] array4 = new byte[114];
Dom4(xof, phflag, ctx);
xof.BlockUpdate(array, 0, 57);
xof.BlockUpdate(array3, 0, 57);
xof.BlockUpdate(m, mOff, mLen);
xof.OutputFinal(array4, 0, array4.Length);
byte[] k = Scalar448.Reduce912(array4);
uint[] array5 = new uint[14];
Scalar448.Decode(k, array5);
uint[] array6 = new uint[8];
uint[] array7 = new uint[8];
if (!Scalar448.ReduceBasisVar(array5, array6, array7))
throw new InvalidOperationException();
Scalar448.Multiply225Var(array2, array7, array2);
Init(out PointProjective r3);
ScalarMultStraus225Var(array2, array6, ref r2, array7, ref r, ref r3);
return NormalizeToNeutralElementVar(ref r3);
}
private static void Init(out PointAffine r)
{
r.x = X448Field.Create();
r.y = X448Field.Create();
}
private static void Init(out PointProjective r)
{
r.x = X448Field.Create();
r.y = X448Field.Create();
r.z = X448Field.Create();
}
private static void Init(out PointTemp r)
{
r.r0 = X448Field.Create();
r.r1 = X448Field.Create();
r.r2 = X448Field.Create();
r.r3 = X448Field.Create();
r.r4 = X448Field.Create();
r.r5 = X448Field.Create();
r.r6 = X448Field.Create();
r.r7 = X448Field.Create();
}
private static void InvertZs(PointProjective[] points)
{
int num = points.Length;
uint[] array = X448Field.CreateTable(num);
uint[] array2 = X448Field.Create();
X448Field.Copy(points[0].z, 0, array2, 0);
X448Field.Copy(array2, 0, array, 0);
int num2 = 0;
while (++num2 < num) {
X448Field.Mul(array2, points[num2].z, array2);
X448Field.Copy(array2, 0, array, num2 * 16);
}
X448Field.InvVar(array2, array2);
num2--;
uint[] array3 = X448Field.Create();
while (num2 > 0) {
int num4 = num2--;
X448Field.Copy(array, num2 * 16, array3, 0);
X448Field.Mul(array3, array2, array3);
X448Field.Mul(array2, points[num4].z, array2);
X448Field.Copy(array3, 0, points[num4].z, 0);
}
X448Field.Copy(array2, 0, points[0].z, 0);
}
private static void NormalizeToAffine(ref PointProjective p, ref PointAffine r)
{
X448Field.Inv(p.z, r.y);
X448Field.Mul(r.y, p.x, r.x);
X448Field.Mul(r.y, p.y, r.y);
X448Field.Normalize(r.x);
X448Field.Normalize(r.y);
}
private static bool NormalizeToNeutralElementVar(ref PointProjective p)
{
X448Field.Normalize(p.x);
X448Field.Normalize(p.y);
X448Field.Normalize(p.z);
if (X448Field.IsZeroVar(p.x) && !X448Field.IsZeroVar(p.y))
return X448Field.AreEqualVar(p.y, p.z);
return false;
}
private static void PointAdd(ref PointAffine p, ref PointProjective r, ref PointTemp t)
{
uint[] r2 = t.r1;
uint[] r3 = t.r2;
uint[] r4 = t.r3;
uint[] r5 = t.r4;
uint[] r6 = t.r5;
uint[] r7 = t.r6;
uint[] r8 = t.r7;
X448Field.Sqr(r.z, r2);
X448Field.Mul(p.x, r.x, r3);
X448Field.Mul(p.y, r.y, r4);
X448Field.Mul(r3, r4, r5);
X448Field.Mul(r5, 39081, r5);
X448Field.Add(r2, r5, r6);
X448Field.Sub(r2, r5, r7);
X448Field.Add(p.y, p.x, r8);
X448Field.Add(r.y, r.x, r5);
X448Field.Mul(r8, r5, r8);
X448Field.Add(r4, r3, r2);
X448Field.Sub(r4, r3, r5);
X448Field.Carry(r2);
X448Field.Sub(r8, r2, r8);
X448Field.Mul(r8, r.z, r8);
X448Field.Mul(r5, r.z, r5);
X448Field.Mul(r6, r8, r.x);
X448Field.Mul(r5, r7, r.y);
X448Field.Mul(r6, r7, r.z);
}
private static void PointAdd(ref PointProjective p, ref PointProjective r, ref PointTemp t)
{
uint[] r2 = t.r0;
uint[] r3 = t.r1;
uint[] r4 = t.r2;
uint[] r5 = t.r3;
uint[] r6 = t.r4;
uint[] r7 = t.r5;
uint[] r8 = t.r6;
uint[] r9 = t.r7;
X448Field.Mul(p.z, r.z, r2);
X448Field.Sqr(r2, r3);
X448Field.Mul(p.x, r.x, r4);
X448Field.Mul(p.y, r.y, r5);
X448Field.Mul(r4, r5, r6);
X448Field.Mul(r6, 39081, r6);
X448Field.Add(r3, r6, r7);
X448Field.Sub(r3, r6, r8);
X448Field.Add(p.y, p.x, r9);
X448Field.Add(r.y, r.x, r6);
X448Field.Mul(r9, r6, r9);
X448Field.Add(r5, r4, r3);
X448Field.Sub(r5, r4, r6);
X448Field.Carry(r3);
X448Field.Sub(r9, r3, r9);
X448Field.Mul(r9, r2, r9);
X448Field.Mul(r6, r2, r6);
X448Field.Mul(r7, r9, r.x);
X448Field.Mul(r6, r8, r.y);
X448Field.Mul(r7, r8, r.z);
}
private static void PointAddVar(bool negate, ref PointAffine p, ref PointProjective r, ref PointTemp t)
{
uint[] r2 = t.r1;
uint[] r3 = t.r2;
uint[] r4 = t.r3;
uint[] r5 = t.r4;
uint[] r6 = t.r5;
uint[] r7 = t.r6;
uint[] r8 = t.r7;
uint[] z;
uint[] z2;
uint[] z3;
uint[] z4;
if (negate) {
z = r5;
z2 = r2;
z3 = r7;
z4 = r6;
X448Field.Sub(p.y, p.x, r8);
} else {
z = r2;
z2 = r5;
z3 = r6;
z4 = r7;
X448Field.Add(p.y, p.x, r8);
}
X448Field.Sqr(r.z, r2);
X448Field.Mul(p.x, r.x, r3);
X448Field.Mul(p.y, r.y, r4);
X448Field.Mul(r3, r4, r5);
X448Field.Mul(r5, 39081, r5);
X448Field.Add(r2, r5, z3);
X448Field.Sub(r2, r5, z4);
X448Field.Add(r.y, r.x, r5);
X448Field.Mul(r8, r5, r8);
X448Field.Add(r4, r3, z);
X448Field.Sub(r4, r3, z2);
X448Field.Carry(z);
X448Field.Sub(r8, r2, r8);
X448Field.Mul(r8, r.z, r8);
X448Field.Mul(r5, r.z, r5);
X448Field.Mul(r6, r8, r.x);
X448Field.Mul(r5, r7, r.y);
X448Field.Mul(r6, r7, r.z);
}
private static void PointAddVar(bool negate, ref PointProjective p, ref PointProjective r, ref PointTemp t)
{
uint[] r2 = t.r0;
uint[] r3 = t.r1;
uint[] r4 = t.r2;
uint[] r5 = t.r3;
uint[] r6 = t.r4;
uint[] r7 = t.r5;
uint[] r8 = t.r6;
uint[] r9 = t.r7;
uint[] z;
uint[] z2;
uint[] z3;
uint[] z4;
if (negate) {
z = r6;
z2 = r3;
z3 = r8;
z4 = r7;
X448Field.Sub(p.y, p.x, r9);
} else {
z = r3;
z2 = r6;
z3 = r7;
z4 = r8;
X448Field.Add(p.y, p.x, r9);
}
X448Field.Mul(p.z, r.z, r2);
X448Field.Sqr(r2, r3);
X448Field.Mul(p.x, r.x, r4);
X448Field.Mul(p.y, r.y, r5);
X448Field.Mul(r4, r5, r6);
X448Field.Mul(r6, 39081, r6);
X448Field.Add(r3, r6, z3);
X448Field.Sub(r3, r6, z4);
X448Field.Add(r.y, r.x, r6);
X448Field.Mul(r9, r6, r9);
X448Field.Add(r5, r4, z);
X448Field.Sub(r5, r4, z2);
X448Field.Carry(z);
X448Field.Sub(r9, r3, r9);
X448Field.Mul(r9, r2, r9);
X448Field.Mul(r6, r2, r6);
X448Field.Mul(r7, r9, r.x);
X448Field.Mul(r6, r8, r.y);
X448Field.Mul(r7, r8, r.z);
}
private static void PointCopy(ref PointAffine p, ref PointProjective r)
{
X448Field.Copy(p.x, 0, r.x, 0);
X448Field.Copy(p.y, 0, r.y, 0);
X448Field.One(r.z);
}
private static void PointCopy(ref PointProjective p, ref PointProjective r)
{
X448Field.Copy(p.x, 0, r.x, 0);
X448Field.Copy(p.y, 0, r.y, 0);
X448Field.Copy(p.z, 0, r.z, 0);
}
private static void PointDouble(ref PointProjective r, ref PointTemp t)
{
uint[] r2 = t.r1;
uint[] r3 = t.r2;
uint[] r4 = t.r3;
uint[] r5 = t.r4;
uint[] r6 = t.r7;
uint[] r7 = t.r0;
X448Field.Add(r.x, r.y, r2);
X448Field.Sqr(r2, r2);
X448Field.Sqr(r.x, r3);
X448Field.Sqr(r.y, r4);
X448Field.Add(r3, r4, r5);
X448Field.Carry(r5);
X448Field.Sqr(r.z, r6);
X448Field.Add(r6, r6, r6);
X448Field.Carry(r6);
X448Field.Sub(r5, r6, r7);
X448Field.Sub(r2, r5, r2);
X448Field.Sub(r3, r4, r3);
X448Field.Mul(r2, r7, r.x);
X448Field.Mul(r5, r3, r.y);
X448Field.Mul(r5, r7, r.z);
}
private static void PointLookup(int block, int index, ref PointAffine p)
{
int num = block * 16 * 2 * 16;
for (int i = 0; i < 16; i++) {
int cond = (i ^ index) - 1 >> 31;
X448Field.CMov(cond, PrecompBaseComb, num, p.x, 0);
num += 16;
X448Field.CMov(cond, PrecompBaseComb, num, p.y, 0);
num += 16;
}
}
private static void PointLookup(uint[] x, int n, uint[] table, ref PointProjective r)
{
uint window = GetWindow4(x, n);
int num = (int)((window >> 3) ^ 1);
int num2 = ((int)window ^ -num) & 7;
int i = 0;
int num3 = 0;
for (; i < 8; i++) {
int cond = (i ^ num2) - 1 >> 31;
X448Field.CMov(cond, table, num3, r.x, 0);
num3 += 16;
X448Field.CMov(cond, table, num3, r.y, 0);
num3 += 16;
X448Field.CMov(cond, table, num3, r.z, 0);
num3 += 16;
}
X448Field.CNegate(num, r.x);
}
private static void PointLookup15(uint[] table, ref PointProjective r)
{
int num = 336;
X448Field.Copy(table, num, r.x, 0);
num += 16;
X448Field.Copy(table, num, r.y, 0);
num += 16;
X448Field.Copy(table, num, r.z, 0);
}
private static uint[] PointPrecompute(ref PointProjective p, int count, ref PointTemp t)
{
Init(out PointProjective r);
PointCopy(ref p, ref r);
Init(out PointProjective r2);
PointCopy(ref p, ref r2);
PointDouble(ref r2, ref t);
uint[] array = X448Field.CreateTable(count * 3);
int num = 0;
int num2 = 0;
while (true) {
X448Field.Copy(r.x, 0, array, num);
num += 16;
X448Field.Copy(r.y, 0, array, num);
num += 16;
X448Field.Copy(r.z, 0, array, num);
num += 16;
if (++num2 == count)
break;
PointAdd(ref r2, ref r, ref t);
}
return array;
}
private static void PointPrecompute(ref PointAffine p, PointProjective[] points, int pointsOff, int pointsLen, ref PointTemp t)
{
Init(out PointProjective r);
PointCopy(ref p, ref r);
PointDouble(ref r, ref t);
Init(out points[pointsOff]);
PointCopy(ref p, ref points[pointsOff]);
for (int i = 1; i < pointsLen; i++) {
Init(out points[pointsOff + i]);
PointCopy(ref points[pointsOff + i - 1], ref points[pointsOff + i]);
PointAdd(ref r, ref points[pointsOff + i], ref t);
}
}
private static void PointSetNeutral(ref PointProjective p)
{
X448Field.Zero(p.x);
X448Field.One(p.y);
X448Field.One(p.z);
}
public static void Precompute()
{
lock (PrecompLock) {
if (PrecompBaseComb == null) {
int num = 32;
int num2 = 80;
int num3 = num * 2 + num2;
PointProjective[] array = new PointProjective[num3];
Init(out PointTemp r);
Init(out PointAffine r2);
X448Field.Copy(B_x, 0, r2.x, 0);
X448Field.Copy(B_y, 0, r2.y, 0);
PointPrecompute(ref r2, array, 0, num, ref r);
Init(out PointAffine r3);
X448Field.Copy(B225_x, 0, r3.x, 0);
X448Field.Copy(B225_y, 0, r3.y, 0);
PointPrecompute(ref r3, array, num, num, ref r);
Init(out PointProjective r4);
PointCopy(ref r2, ref r4);
int num4 = num * 2;
PointProjective[] array2 = new PointProjective[5];
for (int i = 0; i < 5; i++) {
Init(out array2[i]);
}
for (int j = 0; j < 5; j++) {
ref PointProjective reference = ref array[num4++];
Init(out reference);
for (int k = 0; k < 5; k++) {
if (k == 0)
PointCopy(ref r4, ref reference);
else
PointAdd(ref r4, ref reference, ref r);
PointDouble(ref r4, ref r);
PointCopy(ref r4, ref array2[k]);
if (j + k != 8) {
for (int l = 1; l < 18; l++) {
PointDouble(ref r4, ref r);
}
}
}
X448Field.Negate(reference.x, reference.x);
for (int m = 0; m < 4; m++) {
int num6 = 1 << m;
int num7 = 0;
while (num7 < num6) {
Init(out array[num4]);
PointCopy(ref array[num4 - num6], ref array[num4]);
PointAdd(ref array2[m], ref array[num4], ref r);
num7++;
num4++;
}
}
}
InvertZs(array);
PrecompBaseWnaf = new PointAffine[num];
for (int n = 0; n < num; n++) {
ref PointProjective reference2 = ref array[n];
ref PointAffine reference3 = ref PrecompBaseWnaf[n];
Init(out reference3);
X448Field.Mul(reference2.x, reference2.z, reference3.x);
X448Field.Normalize(reference3.x);
X448Field.Mul(reference2.y, reference2.z, reference3.y);
X448Field.Normalize(reference3.y);
}
PrecompBase225Wnaf = new PointAffine[num];
for (int num8 = 0; num8 < num; num8++) {
ref PointProjective reference4 = ref array[num + num8];
ref PointAffine reference5 = ref PrecompBase225Wnaf[num8];
Init(out reference5);
X448Field.Mul(reference4.x, reference4.z, reference5.x);
X448Field.Normalize(reference5.x);
X448Field.Mul(reference4.y, reference4.z, reference5.y);
X448Field.Normalize(reference5.y);
}
PrecompBaseComb = X448Field.CreateTable(num2 * 2);
int num9 = 0;
for (int num10 = num * 2; num10 < num3; num10++) {
ref PointProjective reference6 = ref array[num10];
X448Field.Mul(reference6.x, reference6.z, reference6.x);
X448Field.Normalize(reference6.x);
X448Field.Mul(reference6.y, reference6.z, reference6.y);
X448Field.Normalize(reference6.y);
X448Field.Copy(reference6.x, 0, PrecompBaseComb, num9);
num9 += 16;
X448Field.Copy(reference6.y, 0, PrecompBaseComb, num9);
num9 += 16;
}
}
}
}
private static void PruneScalar(byte[] n, int nOff, byte[] r)
{
Array.Copy(n, nOff, r, 0, 56);
r[0] &= 252;
r[55] |= 128;
r[56] = 0;
}
private static void ScalarMult(byte[] k, ref PointProjective p, ref PointProjective r)
{
uint[] array = new uint[15];
Scalar448.Decode(k, array);
Scalar448.ToSignedDigits(449, array, array);
Init(out PointProjective r2);
Init(out PointTemp r3);
uint[] table = PointPrecompute(ref p, 8, ref r3);
PointLookup15(table, ref r);
PointAdd(ref p, ref r, ref r3);
int num = 111;
while (true) {
PointLookup(array, num, table, ref r2);
PointAdd(ref r2, ref r, ref r3);
if (--num < 0)
break;
for (int i = 0; i < 4; i++) {
PointDouble(ref r, ref r3);
}
}
}
private static void ScalarMultBase(byte[] k, ref PointProjective r)
{
Precompute();
uint[] array = new uint[15];
Scalar448.Decode(k, array);
Scalar448.ToSignedDigits(450, array, array);
Init(out PointAffine r2);
Init(out PointTemp r3);
PointSetNeutral(ref r);
int num = 17;
while (true) {
int num2 = num;
for (int i = 0; i < 5; i++) {
uint num3 = 0;
for (int j = 0; j < 5; j++) {
uint num4 = array[num2 >> 5] >> num2;
num3 = (uint)((int)num3 & ~(1 << j));
num3 ^= num4 << j;
num2 += 18;
}
int num5 = (int)((num3 >> 4) & 1);
int index = ((int)num3 ^ -num5) & 15;
PointLookup(i, index, ref r2);
X448Field.CNegate(num5, r2.x);
PointAdd(ref r2, ref r, ref r3);
}
if (--num < 0)
break;
PointDouble(ref r, ref r3);
}
}
private static void ScalarMultBaseEncoded(byte[] k, byte[] r, int rOff)
{
Init(out PointProjective r2);
ScalarMultBase(k, ref r2);
if (EncodeResult(ref r2, r, rOff) == 0)
throw new InvalidOperationException();
}
internal static void ScalarMultBaseXY(byte[] k, int kOff, uint[] x, uint[] y)
{
byte[] array = new byte[57];
PruneScalar(k, kOff, array);
Init(out PointProjective r);
ScalarMultBase(array, ref r);
if (CheckPoint(r) == 0)
throw new InvalidOperationException();
X448Field.Copy(r.x, 0, x, 0);
X448Field.Copy(r.y, 0, y, 0);
}
private static void ScalarMultOrderVar(ref PointAffine p, ref PointProjective r)
{
sbyte[] array = new sbyte[447];
Scalar448.GetOrderWnafVar(5, array);
int num = 8;
PointProjective[] array2 = new PointProjective[num];
Init(out PointTemp r2);
PointPrecompute(ref p, array2, 0, num, ref r2);
PointSetNeutral(ref r);
int num2 = 446;
while (true) {
int num3 = array[num2];
if (num3 != 0) {
int num4 = (num3 >> 1) ^ (num3 >> 31);
PointAddVar(num3 < 0, ref array2[num4], ref r, ref r2);
}
if (--num2 < 0)
break;
PointDouble(ref r, ref r2);
}
}
private static void ScalarMultStraus225Var(uint[] nb, uint[] np, ref PointAffine p, uint[] nq, ref PointAffine q, ref PointProjective r)
{
Precompute();
sbyte[] array = new sbyte[450];
sbyte[] array2 = new sbyte[225];
sbyte[] array3 = new sbyte[225];
Wnaf.GetSignedVar(nb, 7, array);
Wnaf.GetSignedVar(np, 5, array2);
Wnaf.GetSignedVar(nq, 5, array3);
int num = 8;
PointProjective[] array4 = new PointProjective[num];
PointProjective[] array5 = new PointProjective[num];
Init(out PointTemp r2);
PointPrecompute(ref p, array4, 0, num, ref r2);
PointPrecompute(ref q, array5, 0, num, ref r2);
PointSetNeutral(ref r);
int num2 = 225;
while (--num2 >= 0 && (array[num2] | array[225 + num2] | array2[num2] | array3[num2]) == 0) {
}
while (num2 >= 0) {
int num3 = array[num2];
if (num3 != 0) {
int num4 = (num3 >> 1) ^ (num3 >> 31);
PointAddVar(num3 < 0, ref PrecompBaseWnaf[num4], ref r, ref r2);
}
int num5 = array[225 + num2];
if (num5 != 0) {
int num6 = (num5 >> 1) ^ (num5 >> 31);
PointAddVar(num5 < 0, ref PrecompBase225Wnaf[num6], ref r, ref r2);
}
int num7 = array2[num2];
if (num7 != 0) {
int num8 = (num7 >> 1) ^ (num7 >> 31);
PointAddVar(num7 < 0, ref array4[num8], ref r, ref r2);
}
int num9 = array3[num2];
if (num9 != 0) {
int num10 = (num9 >> 1) ^ (num9 >> 31);
PointAddVar(num9 < 0, ref array5[num10], ref r, ref r2);
}
PointDouble(ref r, ref r2);
num2--;
}
PointDouble(ref r, ref r2);
}
public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
byte phflag = 0;
ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
byte phflag = 0;
ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
{
byte phflag = 1;
ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
}
public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
{
byte phflag = 1;
ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
}
public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IXof ph, byte[] sig, int sigOff)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.OutputFinal(array, 0, PrehashSize))
throw new ArgumentException("ph");
byte phflag = 1;
ImplSign(sk, skOff, ctx, phflag, array, 0, array.Length, sig, sigOff);
}
public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IXof ph, byte[] sig, int sigOff)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.OutputFinal(array, 0, PrehashSize))
throw new ArgumentException("ph");
byte phflag = 1;
ImplSign(sk, skOff, pk, pkOff, ctx, phflag, array, 0, array.Length, sig, sigOff);
}
public static bool ValidatePublicKeyFull(byte[] pk, int pkOff)
{
byte[] p = Copy(pk, pkOff, PublicKeySize);
if (!CheckPointFullVar(p))
return false;
Init(out PointAffine r);
if (!DecodePointVar(p, false, ref r))
return false;
return CheckPointOrderVar(ref r);
}
public static PublicPoint ValidatePublicKeyFullExport(byte[] pk, int pkOff)
{
byte[] p = Copy(pk, pkOff, PublicKeySize);
if (!CheckPointFullVar(p))
return null;
Init(out PointAffine r);
if (!DecodePointVar(p, false, ref r))
return null;
if (!CheckPointOrderVar(ref r))
return null;
return ExportPoint(ref r);
}
public static bool ValidatePublicKeyPartial(byte[] pk, int pkOff)
{
byte[] p = Copy(pk, pkOff, PublicKeySize);
if (!CheckPointFullVar(p))
return false;
Init(out PointAffine r);
return DecodePointVar(p, false, ref r);
}
public static PublicPoint ValidatePublicKeyPartialExport(byte[] pk, int pkOff)
{
byte[] p = Copy(pk, pkOff, PublicKeySize);
if (!CheckPointFullVar(p))
return null;
Init(out PointAffine r);
if (!DecodePointVar(p, false, ref r))
return null;
return ExportPoint(ref r);
}
public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)
{
byte phflag = 0;
return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
}
public static bool Verify(byte[] sig, int sigOff, PublicPoint publicPoint, byte[] ctx, byte[] m, int mOff, int mLen)
{
byte phflag = 0;
return ImplVerify(sig, sigOff, publicPoint, ctx, phflag, m, mOff, mLen);
}
public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff)
{
byte phflag = 1;
return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize);
}
public static bool VerifyPrehash(byte[] sig, int sigOff, PublicPoint publicPoint, byte[] ctx, byte[] ph, int phOff)
{
byte phflag = 1;
return ImplVerify(sig, sigOff, publicPoint, ctx, phflag, ph, phOff, PrehashSize);
}
public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IXof ph)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.OutputFinal(array, 0, PrehashSize))
throw new ArgumentException("ph");
byte phflag = 1;
return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, array, 0, array.Length);
}
public static bool VerifyPrehash(byte[] sig, int sigOff, PublicPoint publicPoint, byte[] ctx, IXof ph)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.OutputFinal(array, 0, PrehashSize))
throw new ArgumentException("ph");
byte phflag = 1;
return ImplVerify(sig, sigOff, publicPoint, ctx, phflag, array, 0, array.Length);
}
}
}