Ed25519
A low-level implementation of the Ed25519, Ed25519ctx, and Ed25519ph 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 Org.BouncyCastle.Utilities;
using System;
using System.Runtime.InteropServices;
namespace Org.BouncyCastle.Math.EC.Rfc8032
{
public static class Ed25519
{
public enum Algorithm
{
Ed25519,
Ed25519ctx,
Ed25519ph
}
public sealed class PublicPoint
{
internal readonly int[] m_data;
internal PublicPoint(int[] data)
{
m_data = data;
}
}
private struct PointAccum
{
internal int[] x;
internal int[] y;
internal int[] z;
internal int[] u;
internal int[] v;
}
private struct PointAffine
{
internal int[] x;
internal int[] y;
}
private struct PointExtended
{
internal int[] x;
internal int[] y;
internal int[] z;
internal int[] t;
}
private struct PointPrecomp
{
internal int[] ymx_h;
internal int[] ypx_h;
internal int[] xyd;
}
private struct PointPrecompZ
{
internal int[] ymx_h;
internal int[] ypx_h;
internal int[] xyd;
internal int[] z;
}
private struct PointTemp
{
internal int[] r0;
internal int[] r1;
}
private const int CoordUints = 8;
private const int PointBytes = 32;
private const int ScalarUints = 8;
private const int ScalarBytes = 32;
public static readonly int PrehashSize = 64;
public static readonly int PublicKeySize = 32;
public static readonly int SecretKeySize = 32;
public static readonly int SignatureSize = 64;
private static readonly byte[] Dom2Prefix = new byte[32] {
83,
105,
103,
69,
100,
50,
53,
53,
49,
57,
32,
110,
111,
32,
69,
100,
50,
53,
53,
49,
57,
32,
99,
111,
108,
108,
105,
115,
105,
111,
110,
115
};
private static readonly uint[] P = new uint[8] {
4294967277,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
uint.MaxValue,
2147483647
};
private static readonly uint[] Order8_y1 = new uint[8] {
1886001095,
1339575613,
1980447930,
258412557,
4199751722,
3335272748,
2013120334,
2047061138
};
private static readonly uint[] Order8_y2 = new uint[8] {
2408966182,
2955391682,
2314519365,
4036554738,
95215573,
959694547,
2281846961,
100422509
};
private static readonly int[] B_x = new int[10] {
52811034,
25909283,
8072341,
50637101,
13785486,
30858332,
20483199,
20966410,
43936626,
4379245
};
private static readonly int[] B_y = new int[10] {
40265304,
26843545,
6710886,
53687091,
13421772,
40265318,
26843545,
6710886,
53687091,
13421772
};
private static readonly int[] B128_x = new int[10] {
12052516,
1174424,
4087752,
38672185,
20040971,
21899680,
55468344,
20105554,
66708015,
9981791
};
private static readonly int[] B128_y = new int[10] {
66430571,
45040722,
4842939,
15895846,
18981244,
46308410,
4697481,
8903007,
53646190,
12474675
};
private static readonly int[] C_d = new int[10] {
56195235,
47411844,
25868126,
40503822,
57364,
58321048,
30416477,
31930572,
57760639,
10749657
};
private static readonly int[] C_d2 = new int[10] {
45281625,
27714825,
18181821,
13898781,
114729,
49533232,
60832955,
30306712,
48412415,
4722099
};
private static readonly int[] C_d4 = new int[10] {
23454386,
55429651,
2809210,
27797563,
229458,
31957600,
54557047,
27058993,
29715967,
9444199
};
private const int WnafWidth128 = 4;
private const int WnafWidthBase = 6;
private const int PrecompBlocks = 8;
private const int PrecompTeeth = 4;
private const int PrecompSpacing = 8;
private const int PrecompRange = 256;
private const int PrecompPoints = 8;
private const int PrecompMask = 7;
private static readonly object PrecompLock = new object();
private static PointPrecomp[] PrecompBaseWnaf = null;
private static PointPrecomp[] PrecompBase128Wnaf = null;
private static int[] PrecompBaseComb = null;
private static byte[] CalculateS(byte[] r, byte[] k, byte[] s)
{
byte[] array = new byte[32];
CalculateS(r, k, s, array);
return array;
}
private unsafe static void CalculateS(ReadOnlySpan<byte> r, ReadOnlySpan<byte> k, ReadOnlySpan<byte> s, Span<byte> S)
{
Span<uint> span = new Span<uint>(stackalloc byte[64], 16);
Scalar25519.Decode(r, span);
Span<uint> span2 = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(k, span2);
Span<uint> span3 = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(s, span3);
Nat256.MulAddTo(span2, span3, span);
if (BitConverter.IsLittleEndian)
Scalar25519.Reduce512(MemoryMarshal.AsBytes(span), S);
else {
Span<byte> span4 = new Span<byte>(stackalloc byte[64], 64);
Codec.Encode32(span, span4);
Scalar25519.Reduce512(span4, S);
}
}
private static bool CheckContextVar(byte[] ctx, byte phflag)
{
if (ctx != null || phflag != 0) {
if (ctx != null)
return ctx.Length < 256;
return false;
}
return true;
}
private static int CheckPoint(ref PointAffine p)
{
int[] array = X25519Field.Create();
int[] array2 = X25519Field.Create();
int[] array3 = X25519Field.Create();
X25519Field.Sqr(p.x, array2);
X25519Field.Sqr(p.y, array3);
X25519Field.Mul(array2, array3, array);
X25519Field.Sub(array2, array3, array2);
X25519Field.Mul(array, C_d, array);
X25519Field.AddOne(array);
X25519Field.Add(array, array2, array);
X25519Field.Normalize(array);
X25519Field.Normalize(array3);
return X25519Field.IsZero(array) & ~X25519Field.IsZero(array3);
}
private static int CheckPoint(PointAccum p)
{
int[] array = X25519Field.Create();
int[] array2 = X25519Field.Create();
int[] array3 = X25519Field.Create();
int[] array4 = X25519Field.Create();
X25519Field.Sqr(p.x, array2);
X25519Field.Sqr(p.y, array3);
X25519Field.Sqr(p.z, array4);
X25519Field.Mul(array2, array3, array);
X25519Field.Sub(array2, array3, array2);
X25519Field.Mul(array2, array4, array2);
X25519Field.Sqr(array4, array4);
X25519Field.Mul(array, C_d, array);
X25519Field.Add(array, array4, array);
X25519Field.Add(array, array2, array);
X25519Field.Normalize(array);
X25519Field.Normalize(array3);
X25519Field.Normalize(array4);
return X25519Field.IsZero(array) & ~X25519Field.IsZero(array3) & ~X25519Field.IsZero(array4);
}
private static bool CheckPointFullVar(ReadOnlySpan<byte> p)
{
uint num;
uint num2 = num = (Codec.Decode32(p.Slice(28, p.Length - 28)) & 2147483647);
uint num3 = num2 ^ P[7];
uint num4 = num2 ^ Order8_y1[7];
uint num5 = num2 ^ Order8_y2[7];
for (int num6 = 6; num6 > 0; num6--) {
int num7 = num6 * 4;
uint num8 = Codec.Decode32(p.Slice(num7, p.Length - num7));
num |= num8;
num3 |= (num8 ^ P[num6]);
num4 |= (num8 ^ Order8_y1[num6]);
num5 |= (num8 ^ Order8_y2[num6]);
}
uint num9 = Codec.Decode32(p);
if (num == 0 && num9 <= 1)
return false;
if (num3 == 0 && num9 >= P[0] - 1)
return false;
num4 |= (num9 ^ Order8_y1[0]);
num5 |= (num9 ^ Order8_y2[0]);
return (num4 != 0) & (num5 != 0);
}
private static bool CheckPointOrderVar(ref PointAffine p)
{
Init(out PointAccum r);
ScalarMultOrderVar(ref p, ref r);
return NormalizeToNeutralElementVar(ref r);
}
private static bool CheckPointVar(ReadOnlySpan<byte> p)
{
if ((Codec.Decode32(p.Slice(28, p.Length - 28)) & 2147483647) < P[7])
return true;
for (int num = 6; num >= 0; num--) {
int num2 = num * 4;
if (Codec.Decode32(p.Slice(num2, p.Length - num2)) < P[num])
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;
}
private static IDigest CreateDigest()
{
Sha512Digest sha512Digest = new Sha512Digest();
if (sha512Digest.GetDigestSize() != 64)
throw new InvalidOperationException();
return sha512Digest;
}
public static IDigest CreatePrehash()
{
return CreateDigest();
}
private static bool DecodePointVar(ReadOnlySpan<byte> p, bool negate, ref PointAffine r)
{
int num = (p[31] & 128) >> 7;
X25519Field.Decode(p, r.y);
int[] array = X25519Field.Create();
int[] array2 = X25519Field.Create();
X25519Field.Sqr(r.y, array);
X25519Field.Mul(C_d, array, array2);
X25519Field.SubOne(array);
X25519Field.AddOne(array2);
if (!X25519Field.SqrtRatioVar(array, array2, r.x))
return false;
X25519Field.Normalize(r.x);
if (num == 1 && X25519Field.IsZeroVar(r.x))
return false;
if (negate ^ (num != (r.x[0] & 1))) {
X25519Field.Negate(r.x, r.x);
X25519Field.Normalize(r.x);
}
return true;
}
private unsafe static void Dom2(IDigest d, byte phflag, byte[] ctx)
{
int num = Dom2Prefix.Length;
int num2 = num + 2 + ctx.Length;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
Dom2Prefix.CopyTo(span);
span[num] = phflag;
span[num + 1] = (byte)ctx.Length;
ctx.CopyTo(span.Slice(num + 2));
d.BlockUpdate(span);
}
private static void EncodePoint(ref PointAffine p, byte[] r, int rOff)
{
X25519Field.Encode(p.y, r, rOff);
r[rOff + 32 - 1] |= (byte)((p.x[0] & 1) << 7);
}
private static void EncodePoint(ref PointAffine p, Span<byte> r)
{
X25519Field.Encode(p.y, r);
r[31] |= (byte)((p.x[0] & 1) << 7);
}
public static void EncodePublicPoint(PublicPoint publicPoint, byte[] pk, int pkOff)
{
X25519Field.Encode(publicPoint.m_data, 10, pk, pkOff);
pk[pkOff + 32 - 1] |= (byte)((publicPoint.m_data[0] & 1) << 7);
}
public static void EncodePublicPoint(PublicPoint publicPoint, Span<byte> pk)
{
X25519Field.Encode(publicPoint.m_data.AsSpan(10), pk);
pk[31] |= (byte)((publicPoint.m_data[0] & 1) << 7);
}
private static int EncodeResult(ref PointAccum p, byte[] r, int rOff)
{
return EncodeResult(ref p, r.AsSpan(rOff));
}
private static int EncodeResult(ref PointAccum p, Span<byte> r)
{
Init(out PointAffine r2);
NormalizeToAffine(ref p, ref r2);
int result = CheckPoint(ref r2);
EncodePoint(ref r2, r);
return result;
}
private static PublicPoint ExportPoint(ref PointAffine p)
{
int[] array = new int[20];
X25519Field.Copy(p.x, 0, array, 0);
X25519Field.Copy(p.y, 0, array, 10);
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 GeneratePrivateKey(SecureRandom random, Span<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)
{
GeneratePublicKey(sk.AsSpan(skOff), pk.AsSpan(pkOff));
}
public unsafe static void GeneratePublicKey(ReadOnlySpan<byte> sk, Span<byte> pk)
{
IDigest digest = CreateDigest();
Span<byte> span = new Span<byte>(stackalloc byte[64], 64);
digest.BlockUpdate(sk.Slice(0, SecretKeySize));
digest.DoFinal(span);
Span<byte> span2 = new Span<byte>(stackalloc byte[32], 32);
PruneScalar(span, span2);
ScalarMultBaseEncoded(span2, pk);
}
public static PublicPoint GeneratePublicKey(byte[] sk, int skOff)
{
return GeneratePublicKey(sk.AsSpan(skOff));
}
public unsafe static PublicPoint GeneratePublicKey(ReadOnlySpan<byte> sk)
{
IDigest digest = CreateDigest();
Span<byte> span = new Span<byte>(stackalloc byte[64], 64);
digest.BlockUpdate(sk.Slice(0, SecretKeySize));
digest.DoFinal(span);
Span<byte> span2 = new Span<byte>(stackalloc byte[32], 32);
PruneScalar(span, span2);
Init(out PointAccum r);
ScalarMultBase(span2, 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(ReadOnlySpan<uint> x, int n)
{
int index = (int)((uint)n >> 3);
int num = (n & 7) << 2;
return (x[index] >> num) & 15;
}
private static void GroupCombBits(Span<uint> n)
{
for (int i = 0; i < n.Length; i++) {
n[i] = Interleave.Shuffle2(n[i]);
}
}
private unsafe static void ImplSign(IDigest d, Span<byte> h, ReadOnlySpan<byte> s, ReadOnlySpan<byte> pk, byte[] ctx, byte phflag, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (ctx != null)
Dom2(d, phflag, ctx);
d.BlockUpdate(h.Slice(32, 32));
d.BlockUpdate(m);
d.DoFinal(h);
Span<byte> span = new Span<byte>(stackalloc byte[32], 32);
Scalar25519.Reduce512(h, span);
Span<byte> span2 = sig.Slice(0, 32);
ScalarMultBaseEncoded(span, span2);
if (ctx != null)
Dom2(d, phflag, ctx);
d.BlockUpdate(span2);
d.BlockUpdate(pk);
d.BlockUpdate(m);
d.DoFinal(h);
Span<byte> span3 = new Span<byte>(stackalloc byte[32], 32);
Scalar25519.Reduce512(h, span3);
Span<byte> s2 = sig.Slice(32, sig.Length - 32);
CalculateS(span, span3, s, s2);
}
private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
ImplSign(sk.AsSpan(skOff, SecretKeySize), ctx, phflag, m.AsSpan(mOff, mLen), sig.AsSpan(sigOff, SignatureSize));
}
private unsafe static void ImplSign(ReadOnlySpan<byte> sk, byte[] ctx, byte phflag, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (!CheckContextVar(ctx, phflag))
throw new ArgumentException("ctx");
IDigest digest = CreateDigest();
Span<byte> span = new Span<byte>(stackalloc byte[64], 64);
digest.BlockUpdate(sk);
digest.DoFinal(span);
Span<byte> span2 = new Span<byte>(stackalloc byte[32], 32);
PruneScalar(span, span2);
Span<byte> span3 = new Span<byte>(stackalloc byte[32], 32);
ScalarMultBaseEncoded(span2, span3);
ImplSign(digest, span, span2, span3, ctx, phflag, m, sig);
}
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)
{
ImplSign(sk.AsSpan(skOff, SecretKeySize), pk.AsSpan(pkOff, PublicKeySize), ctx, phflag, m.AsSpan(mOff, mLen), sig.AsSpan(sigOff, SignatureSize));
}
private unsafe static void ImplSign(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> pk, byte[] ctx, byte phflag, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (!CheckContextVar(ctx, phflag))
throw new ArgumentException("ctx");
IDigest digest = CreateDigest();
Span<byte> span = new Span<byte>(stackalloc byte[64], 64);
digest.BlockUpdate(sk);
digest.DoFinal(span);
Span<byte> span2 = new Span<byte>(stackalloc byte[32], 32);
PruneScalar(span, span2);
ImplSign(digest, span, span2, pk, ctx, phflag, m, sig);
}
private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen)
{
return ImplVerify(sig.AsSpan(sigOff, SignatureSize), pk.AsSpan(pkOff, PublicKeySize), ctx, phflag, m.AsSpan(mOff, mLen));
}
private unsafe static bool ImplVerify(ReadOnlySpan<byte> sig, ReadOnlySpan<byte> pk, byte[] ctx, byte phflag, ReadOnlySpan<byte> m)
{
if (!CheckContextVar(ctx, phflag))
throw new ArgumentException("ctx");
ReadOnlySpan<byte> readOnlySpan = sig.Slice(0, 32);
ReadOnlySpan<byte> s = sig.Slice(32, sig.Length - 32);
if (!CheckPointVar(readOnlySpan))
return false;
Span<uint> span = new Span<uint>(stackalloc byte[32], 8);
if (!Scalar25519.CheckVar(s, span))
return false;
if (!CheckPointFullVar(pk))
return false;
Init(out PointAffine r);
if (!DecodePointVar(readOnlySpan, true, ref r))
return false;
Init(out PointAffine r2);
if (!DecodePointVar(pk, true, ref r2))
return false;
IDigest digest = CreateDigest();
Span<byte> span2 = new Span<byte>(stackalloc byte[64], 64);
if (ctx != null)
Dom2(digest, phflag, ctx);
digest.BlockUpdate(readOnlySpan);
digest.BlockUpdate(pk);
digest.BlockUpdate(m);
digest.DoFinal(span2);
Span<byte> span3 = new Span<byte>(stackalloc byte[32], 32);
Scalar25519.Reduce512(span2, span3);
Span<uint> span4 = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(span3, span4);
Span<uint> span5 = new Span<uint>(stackalloc byte[16], 4);
Span<uint> span6 = new Span<uint>(stackalloc byte[16], 4);
if (!Scalar25519.ReduceBasisVar(span4, span5, span6))
throw new InvalidOperationException();
Scalar25519.Multiply128Var(span, span6, span);
Init(out PointAccum r3);
ScalarMultStraus128Var(span, span5, ref r2, span6, 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)
{
return ImplVerify(sig.AsSpan(sigOff, SignatureSize), publicPoint, ctx, phflag, m.AsSpan(mOff, mLen));
}
private unsafe static bool ImplVerify(ReadOnlySpan<byte> sig, PublicPoint publicPoint, byte[] ctx, byte phflag, ReadOnlySpan<byte> m)
{
if (!CheckContextVar(ctx, phflag))
throw new ArgumentException("ctx");
ReadOnlySpan<byte> readOnlySpan = sig.Slice(0, 32);
ReadOnlySpan<byte> s = sig.Slice(32, sig.Length - 32);
if (!CheckPointVar(readOnlySpan))
return false;
Span<uint> span = new Span<uint>(stackalloc byte[32], 8);
if (!Scalar25519.CheckVar(s, span))
return false;
Init(out PointAffine r);
if (!DecodePointVar(readOnlySpan, true, ref r))
return false;
Init(out PointAffine r2);
X25519Field.Negate(publicPoint.m_data, r2.x);
X25519Field.Copy(publicPoint.m_data.AsSpan(10), r2.y);
int publicKeySize = PublicKeySize;
Span<byte> span2 = new Span<byte>(stackalloc byte[(int)(uint)publicKeySize], publicKeySize);
EncodePublicPoint(publicPoint, span2);
IDigest digest = CreateDigest();
Span<byte> span3 = new Span<byte>(stackalloc byte[64], 64);
if (ctx != null)
Dom2(digest, phflag, ctx);
digest.BlockUpdate(readOnlySpan);
digest.BlockUpdate(span2);
digest.BlockUpdate(m);
digest.DoFinal(span3);
Span<byte> span4 = new Span<byte>(stackalloc byte[32], 32);
Scalar25519.Reduce512(span3, span4);
Span<uint> span5 = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(span4, span5);
Span<uint> span6 = new Span<uint>(stackalloc byte[16], 4);
Span<uint> span7 = new Span<uint>(stackalloc byte[16], 4);
if (!Scalar25519.ReduceBasisVar(span5, span6, span7))
throw new InvalidOperationException();
Scalar25519.Multiply128Var(span, span7, span);
Init(out PointAccum r3);
ScalarMultStraus128Var(span, span6, ref r2, span7, ref r, ref r3);
return NormalizeToNeutralElementVar(ref r3);
}
private static void Init(out PointAccum r)
{
r.x = X25519Field.Create();
r.y = X25519Field.Create();
r.z = X25519Field.Create();
r.u = X25519Field.Create();
r.v = X25519Field.Create();
}
private static void Init(out PointAffine r)
{
r.x = X25519Field.Create();
r.y = X25519Field.Create();
}
private static void Init(out PointExtended r)
{
r.x = X25519Field.Create();
r.y = X25519Field.Create();
r.z = X25519Field.Create();
r.t = X25519Field.Create();
}
private static void Init(out PointPrecomp r)
{
r.ymx_h = X25519Field.Create();
r.ypx_h = X25519Field.Create();
r.xyd = X25519Field.Create();
}
private static void Init(out PointPrecompZ r)
{
r.ymx_h = X25519Field.Create();
r.ypx_h = X25519Field.Create();
r.xyd = X25519Field.Create();
r.z = X25519Field.Create();
}
private static void Init(out PointTemp r)
{
r.r0 = X25519Field.Create();
r.r1 = X25519Field.Create();
}
private static void InvertDoubleZs(PointExtended[] points)
{
int num = points.Length;
int[] array = X25519Field.CreateTable(num);
int[] array2 = X25519Field.Create();
X25519Field.Copy(points[0].z, 0, array2, 0);
X25519Field.Copy(array2, 0, array, 0);
int num2 = 0;
while (++num2 < num) {
X25519Field.Mul(array2, points[num2].z, array2);
X25519Field.Copy(array2, 0, array, num2 * 10);
}
X25519Field.Add(array2, array2, array2);
X25519Field.InvVar(array2, array2);
num2--;
int[] array3 = X25519Field.Create();
while (num2 > 0) {
int num4 = num2--;
X25519Field.Copy(array, num2 * 10, array3, 0);
X25519Field.Mul(array3, array2, array3);
X25519Field.Mul(array2, points[num4].z, array2);
X25519Field.Copy(array3, 0, points[num4].z, 0);
}
X25519Field.Copy(array2, 0, points[0].z, 0);
}
private static void NormalizeToAffine(ref PointAccum p, ref PointAffine r)
{
X25519Field.Inv(p.z, r.y);
X25519Field.Mul(r.y, p.x, r.x);
X25519Field.Mul(r.y, p.y, r.y);
X25519Field.Normalize(r.x);
X25519Field.Normalize(r.y);
}
private static bool NormalizeToNeutralElementVar(ref PointAccum p)
{
X25519Field.Normalize(p.x);
X25519Field.Normalize(p.y);
X25519Field.Normalize(p.z);
if (X25519Field.IsZeroVar(p.x) && !X25519Field.IsZeroVar(p.y))
return X25519Field.AreEqualVar(p.y, p.z);
return false;
}
private static void PointAdd(ref PointExtended p, ref PointExtended q, ref PointExtended r, ref PointTemp t)
{
int[] x = r.x;
int[] y = r.y;
int[] r2 = t.r0;
int[] r3 = t.r1;
int[] array = x;
int[] array2 = r2;
int[] array3 = r3;
int[] array4 = y;
X25519Field.Apm(p.y, p.x, y, x);
X25519Field.Apm(q.y, q.x, r3, r2);
X25519Field.Mul(x, r2, x);
X25519Field.Mul(y, r3, y);
X25519Field.Mul(p.t, q.t, r2);
X25519Field.Mul(r2, C_d2, r2);
X25519Field.Add(p.z, p.z, r3);
X25519Field.Mul(r3, q.z, r3);
X25519Field.Apm(y, x, array4, array);
X25519Field.Apm(r3, r2, array3, array2);
X25519Field.Mul(array, array4, r.t);
X25519Field.Mul(array2, array3, r.z);
X25519Field.Mul(array, array2, r.x);
X25519Field.Mul(array4, array3, r.y);
}
private static void PointAdd(ref PointPrecomp p, ref PointAccum r, ref PointTemp t)
{
int[] x = r.x;
int[] y = r.y;
int[] r2 = t.r0;
int[] u = r.u;
int[] array = x;
int[] array2 = y;
int[] v = r.v;
X25519Field.Apm(r.y, r.x, y, x);
X25519Field.Mul(x, p.ymx_h, x);
X25519Field.Mul(y, p.ypx_h, y);
X25519Field.Mul(r.u, r.v, r2);
X25519Field.Mul(r2, p.xyd, r2);
X25519Field.Apm(y, x, v, u);
X25519Field.Apm(r.z, r2, array2, array);
X25519Field.Mul(array, array2, r.z);
X25519Field.Mul(array, u, r.x);
X25519Field.Mul(array2, v, r.y);
}
private static void PointAdd(ref PointPrecompZ p, ref PointAccum r, ref PointTemp t)
{
int[] x = r.x;
int[] y = r.y;
int[] r2 = t.r0;
int[] z = r.z;
int[] u = r.u;
int[] array = x;
int[] array2 = y;
int[] v = r.v;
X25519Field.Apm(r.y, r.x, y, x);
X25519Field.Mul(x, p.ymx_h, x);
X25519Field.Mul(y, p.ypx_h, y);
X25519Field.Mul(r.u, r.v, r2);
X25519Field.Mul(r2, p.xyd, r2);
X25519Field.Mul(r.z, p.z, z);
X25519Field.Apm(y, x, v, u);
X25519Field.Apm(z, r2, array2, array);
X25519Field.Mul(array, array2, r.z);
X25519Field.Mul(array, u, r.x);
X25519Field.Mul(array2, v, r.y);
}
private static void PointAddVar(bool negate, ref PointPrecomp p, ref PointAccum r, ref PointTemp t)
{
int[] x = r.x;
int[] y = r.y;
int[] r2 = t.r0;
int[] u = r.u;
int[] x2 = x;
int[] array = y;
int[] v = r.v;
int[] array2;
int[] array3;
if (negate) {
array2 = y;
array3 = x;
} else {
array2 = x;
array3 = y;
}
int[] zm = array2;
int[] zp = array3;
X25519Field.Apm(r.y, r.x, y, x);
X25519Field.Mul(array2, p.ymx_h, array2);
X25519Field.Mul(array3, p.ypx_h, array3);
X25519Field.Mul(r.u, r.v, r2);
X25519Field.Mul(r2, p.xyd, r2);
X25519Field.Apm(y, x, v, u);
X25519Field.Apm(r.z, r2, zp, zm);
X25519Field.Mul(x2, array, r.z);
X25519Field.Mul(x2, u, r.x);
X25519Field.Mul(array, v, r.y);
}
private static void PointAddVar(bool negate, ref PointPrecompZ p, ref PointAccum r, ref PointTemp t)
{
int[] x = r.x;
int[] y = r.y;
int[] r2 = t.r0;
int[] z = r.z;
int[] u = r.u;
int[] x2 = x;
int[] array = y;
int[] v = r.v;
int[] array2;
int[] array3;
if (negate) {
array2 = y;
array3 = x;
} else {
array2 = x;
array3 = y;
}
int[] zm = array2;
int[] zp = array3;
X25519Field.Apm(r.y, r.x, y, x);
X25519Field.Mul(array2, p.ymx_h, array2);
X25519Field.Mul(array3, p.ypx_h, array3);
X25519Field.Mul(r.u, r.v, r2);
X25519Field.Mul(r2, p.xyd, r2);
X25519Field.Mul(r.z, p.z, z);
X25519Field.Apm(y, x, v, u);
X25519Field.Apm(z, r2, zp, zm);
X25519Field.Mul(x2, array, r.z);
X25519Field.Mul(x2, u, r.x);
X25519Field.Mul(array, v, r.y);
}
private static void PointCopy(ref PointAccum p, ref PointExtended r)
{
X25519Field.Copy(p.x, 0, r.x, 0);
X25519Field.Copy(p.y, 0, r.y, 0);
X25519Field.Copy(p.z, 0, r.z, 0);
X25519Field.Mul(p.u, p.v, r.t);
}
private static void PointCopy(ref PointAffine p, ref PointExtended r)
{
X25519Field.Copy(p.x, 0, r.x, 0);
X25519Field.Copy(p.y, 0, r.y, 0);
X25519Field.One(r.z);
X25519Field.Mul(p.x, p.y, r.t);
}
private static void PointCopy(ref PointExtended p, ref PointPrecompZ r)
{
X25519Field.Apm(p.y, p.x, r.ypx_h, r.ymx_h);
X25519Field.Mul(p.t, C_d2, r.xyd);
X25519Field.Add(p.z, p.z, r.z);
}
private static void PointDouble(ref PointAccum r)
{
int[] x = r.x;
int[] y = r.y;
int[] z = r.z;
int[] u = r.u;
int[] array = x;
int[] array2 = y;
int[] v = r.v;
X25519Field.Add(r.x, r.y, u);
X25519Field.Sqr(r.x, x);
X25519Field.Sqr(r.y, y);
X25519Field.Sqr(r.z, z);
X25519Field.Add(z, z, z);
X25519Field.Apm(x, y, v, array2);
X25519Field.Sqr(u, u);
X25519Field.Sub(v, u, u);
X25519Field.Add(z, array2, array);
X25519Field.Carry(array);
X25519Field.Mul(array, array2, r.z);
X25519Field.Mul(array, u, r.x);
X25519Field.Mul(array2, v, r.y);
}
private static void PointLookup(int block, int index, ref PointPrecomp p)
{
int num = block * 8 * 3 * 10;
for (int i = 0; i < 8; i++) {
int cond = (i ^ index) - 1 >> 31;
X25519Field.CMov(cond, PrecompBaseComb, num, p.ymx_h, 0);
num += 10;
X25519Field.CMov(cond, PrecompBaseComb, num, p.ypx_h, 0);
num += 10;
X25519Field.CMov(cond, PrecompBaseComb, num, p.xyd, 0);
num += 10;
}
}
private static void PointLookupZ(ReadOnlySpan<uint> x, int n, ReadOnlySpan<int> table, ref PointPrecompZ r)
{
uint window = GetWindow4(x, n);
int num = (int)((window >> 3) ^ 1);
int num2 = ((int)window ^ -num) & 7;
for (int i = 0; i < 8; i++) {
int cond = (i ^ num2) - 1 >> 31;
X25519Field.CMov(cond, table, r.ymx_h);
table = table.Slice(10, table.Length - 10);
X25519Field.CMov(cond, table, r.ypx_h);
table = table.Slice(10, table.Length - 10);
X25519Field.CMov(cond, table, r.xyd);
table = table.Slice(10, table.Length - 10);
X25519Field.CMov(cond, table, r.z);
table = table.Slice(10, table.Length - 10);
}
X25519Field.CSwap(num, r.ymx_h, r.ypx_h);
X25519Field.CNegate(num, r.xyd);
}
private static void PointPrecompute(ref PointAffine p, PointExtended[] points, int pointsOff, int pointsLen, ref PointTemp t)
{
Init(out points[pointsOff]);
PointCopy(ref p, ref points[pointsOff]);
Init(out PointExtended r);
PointAdd(ref points[pointsOff], ref points[pointsOff], ref r, ref t);
for (int i = 1; i < pointsLen; i++) {
Init(out points[pointsOff + i]);
PointAdd(ref points[pointsOff + i - 1], ref r, ref points[pointsOff + i], ref t);
}
}
private static int[] PointPrecomputeZ(ref PointAffine p, int count, ref PointTemp t)
{
Init(out PointExtended r);
PointCopy(ref p, ref r);
Init(out PointExtended r2);
PointAdd(ref r, ref r, ref r2, ref t);
Init(out PointPrecompZ r3);
int[] array = X25519Field.CreateTable(count * 4);
int num = 0;
int num2 = 0;
while (true) {
PointCopy(ref r, ref r3);
X25519Field.Copy(r3.ymx_h, 0, array, num);
num += 10;
X25519Field.Copy(r3.ypx_h, 0, array, num);
num += 10;
X25519Field.Copy(r3.xyd, 0, array, num);
num += 10;
X25519Field.Copy(r3.z, 0, array, num);
num += 10;
if (++num2 == count)
break;
PointAdd(ref r, ref r2, ref r, ref t);
}
return array;
}
private static void PointPrecomputeZ(ref PointAffine p, PointPrecompZ[] points, int count, ref PointTemp t)
{
Init(out PointExtended r);
PointCopy(ref p, ref r);
Init(out PointExtended r2);
PointAdd(ref r, ref r, ref r2, ref t);
int num = 0;
while (true) {
ref PointPrecompZ r3 = ref points[num];
Init(out r3);
PointCopy(ref r, ref r3);
if (++num == count)
break;
PointAdd(ref r, ref r2, ref r, ref t);
}
}
private static void PointSetNeutral(ref PointAccum p)
{
X25519Field.Zero(p.x);
X25519Field.One(p.y);
X25519Field.One(p.z);
X25519Field.Zero(p.u);
X25519Field.One(p.v);
}
public static void Precompute()
{
lock (PrecompLock) {
if (PrecompBaseComb == null) {
int num = 16;
int num2 = 64;
int num3 = num * 2 + num2;
PointExtended[] array = new PointExtended[num3];
Init(out PointTemp r);
Init(out PointAffine r2);
X25519Field.Copy(B_x, 0, r2.x, 0);
X25519Field.Copy(B_y, 0, r2.y, 0);
PointPrecompute(ref r2, array, 0, num, ref r);
Init(out PointAffine r3);
X25519Field.Copy(B128_x, 0, r3.x, 0);
X25519Field.Copy(B128_y, 0, r3.y, 0);
PointPrecompute(ref r3, array, num, num, ref r);
Init(out PointAccum r4);
X25519Field.Copy(B_x, 0, r4.x, 0);
X25519Field.Copy(B_y, 0, r4.y, 0);
X25519Field.One(r4.z);
X25519Field.Copy(B_x, 0, r4.u, 0);
X25519Field.Copy(B_y, 0, r4.v, 0);
int num4 = num * 2;
PointExtended[] array2 = new PointExtended[4];
for (int i = 0; i < 4; i++) {
Init(out array2[i]);
}
Init(out PointExtended r5);
for (int j = 0; j < 8; j++) {
ref PointExtended reference = ref array[num4++];
Init(out reference);
for (int k = 0; k < 4; k++) {
if (k == 0)
PointCopy(ref r4, ref reference);
else {
PointCopy(ref r4, ref r5);
PointAdd(ref reference, ref r5, ref reference, ref r);
}
PointDouble(ref r4);
PointCopy(ref r4, ref array2[k]);
if (j + k != 10) {
for (int l = 1; l < 8; l++) {
PointDouble(ref r4);
}
}
}
X25519Field.Negate(reference.x, reference.x);
X25519Field.Negate(reference.t, reference.t);
for (int m = 0; m < 3; m++) {
int num6 = 1 << m;
int num7 = 0;
while (num7 < num6) {
Init(out array[num4]);
PointAdd(ref array[num4 - num6], ref array2[m], ref array[num4], ref r);
num7++;
num4++;
}
}
}
InvertDoubleZs(array);
PrecompBaseWnaf = new PointPrecomp[num];
for (int n = 0; n < num; n++) {
ref PointExtended reference2 = ref array[n];
ref PointPrecomp reference3 = ref PrecompBaseWnaf[n];
Init(out reference3);
X25519Field.Mul(reference2.x, reference2.z, reference2.x);
X25519Field.Mul(reference2.y, reference2.z, reference2.y);
X25519Field.Apm(reference2.y, reference2.x, reference3.ypx_h, reference3.ymx_h);
X25519Field.Mul(reference2.x, reference2.y, reference3.xyd);
X25519Field.Mul(reference3.xyd, C_d4, reference3.xyd);
X25519Field.Normalize(reference3.ymx_h);
X25519Field.Normalize(reference3.ypx_h);
X25519Field.Normalize(reference3.xyd);
}
PrecompBase128Wnaf = new PointPrecomp[num];
for (int num8 = 0; num8 < num; num8++) {
ref PointExtended reference4 = ref array[num + num8];
ref PointPrecomp reference5 = ref PrecompBase128Wnaf[num8];
Init(out reference5);
X25519Field.Mul(reference4.x, reference4.z, reference4.x);
X25519Field.Mul(reference4.y, reference4.z, reference4.y);
X25519Field.Apm(reference4.y, reference4.x, reference5.ypx_h, reference5.ymx_h);
X25519Field.Mul(reference4.x, reference4.y, reference5.xyd);
X25519Field.Mul(reference5.xyd, C_d4, reference5.xyd);
X25519Field.Normalize(reference5.ymx_h);
X25519Field.Normalize(reference5.ypx_h);
X25519Field.Normalize(reference5.xyd);
}
PrecompBaseComb = X25519Field.CreateTable(num2 * 3);
Init(out PointPrecomp r6);
int num9 = 0;
for (int num10 = num * 2; num10 < num3; num10++) {
ref PointExtended reference6 = ref array[num10];
X25519Field.Mul(reference6.x, reference6.z, reference6.x);
X25519Field.Mul(reference6.y, reference6.z, reference6.y);
X25519Field.Apm(reference6.y, reference6.x, r6.ypx_h, r6.ymx_h);
X25519Field.Mul(reference6.x, reference6.y, r6.xyd);
X25519Field.Mul(r6.xyd, C_d4, r6.xyd);
X25519Field.Normalize(r6.ymx_h);
X25519Field.Normalize(r6.ypx_h);
X25519Field.Normalize(r6.xyd);
X25519Field.Copy(r6.ymx_h, 0, PrecompBaseComb, num9);
num9 += 10;
X25519Field.Copy(r6.ypx_h, 0, PrecompBaseComb, num9);
num9 += 10;
X25519Field.Copy(r6.xyd, 0, PrecompBaseComb, num9);
num9 += 10;
}
}
}
}
private static void PruneScalar(byte[] n, int nOff, byte[] r)
{
Array.Copy(n, nOff, r, 0, 32);
r[0] &= 248;
r[31] &= 127;
r[31] |= 64;
}
private static void PruneScalar(ReadOnlySpan<byte> n, Span<byte> r)
{
n.Slice(0, 32).CopyTo(r);
r[0] &= 248;
r[31] &= 127;
r[31] |= 64;
}
private unsafe static void ScalarMult(ReadOnlySpan<byte> k, ref PointAffine p, ref PointAccum r)
{
Span<uint> span = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(k, span);
Scalar25519.ToSignedDigits(256, span);
Init(out PointPrecompZ r2);
Init(out PointTemp r3);
int[] array = PointPrecomputeZ(ref p, 8, ref r3);
PointSetNeutral(ref r);
int num = 63;
while (true) {
PointLookupZ(span, num, array, ref r2);
PointAdd(ref r2, ref r, ref r3);
if (--num < 0)
break;
for (int i = 0; i < 4; i++) {
PointDouble(ref r);
}
}
}
private unsafe static void ScalarMultBase(ReadOnlySpan<byte> k, ref PointAccum r)
{
Precompute();
Span<uint> span = new Span<uint>(stackalloc byte[32], 8);
Scalar25519.Decode(k, span);
Scalar25519.ToSignedDigits(256, span);
GroupCombBits(span);
Init(out PointPrecomp r2);
Init(out PointTemp r3);
PointSetNeutral(ref r);
int num = 0;
int num2 = 28;
while (true) {
for (int i = 0; i < 8; i++) {
uint num3 = span[i] >> num2;
int num4 = (int)((num3 >> 3) & 1);
int index = ((int)num3 ^ -num4) & 7;
PointLookup(i, index, ref r2);
X25519Field.CNegate(num ^ num4, r.x);
X25519Field.CNegate(num ^ num4, r.u);
num = num4;
PointAdd(ref r2, ref r, ref r3);
}
if ((num2 -= 4) < 0)
break;
PointDouble(ref r);
}
X25519Field.CNegate(num, r.x);
X25519Field.CNegate(num, r.u);
}
private static void ScalarMultBaseEncoded(byte[] k, byte[] r, int rOff)
{
ScalarMultBaseEncoded(k.AsSpan(), r.AsSpan(rOff));
}
private static void ScalarMultBaseEncoded(ReadOnlySpan<byte> k, Span<byte> r)
{
Init(out PointAccum r2);
ScalarMultBase(k, ref r2);
if (EncodeResult(ref r2, r) == 0)
throw new InvalidOperationException();
}
internal static void ScalarMultBaseYZ(byte[] k, int kOff, int[] y, int[] z)
{
ScalarMultBaseYZ(k.AsSpan(kOff), y.AsSpan(), z.AsSpan());
}
internal unsafe static void ScalarMultBaseYZ(ReadOnlySpan<byte> k, Span<int> y, Span<int> z)
{
Span<byte> span = new Span<byte>(stackalloc byte[32], 32);
PruneScalar(k, span);
Init(out PointAccum r);
ScalarMultBase(span, ref r);
if (CheckPoint(r) == 0)
throw new InvalidOperationException();
X25519Field.Copy(r.y, y);
X25519Field.Copy(r.z, z);
}
private unsafe static void ScalarMultOrderVar(ref PointAffine p, ref PointAccum r)
{
Span<sbyte> ws = new Span<sbyte>(stackalloc byte[253], 253);
Scalar25519.GetOrderWnafVar(4, ws);
int num = 4;
PointPrecompZ[] array = new PointPrecompZ[num];
Init(out PointTemp r2);
PointPrecomputeZ(ref p, array, num, ref r2);
PointSetNeutral(ref r);
int num2 = 252;
while (true) {
int num3 = ws[num2];
if (num3 != 0) {
int num4 = (num3 >> 1) ^ (num3 >> 31);
PointAddVar(num3 < 0, ref array[num4], ref r, ref r2);
}
if (--num2 < 0)
break;
PointDouble(ref r);
}
}
private unsafe static void ScalarMultStraus128Var(ReadOnlySpan<uint> nb, ReadOnlySpan<uint> np, ref PointAffine p, ReadOnlySpan<uint> nq, ref PointAffine q, ref PointAccum r)
{
Precompute();
Span<sbyte> ws = new Span<sbyte>(stackalloc byte[256], 256);
Span<sbyte> ws2 = new Span<sbyte>(stackalloc byte[128], 128);
Span<sbyte> ws3 = new Span<sbyte>(stackalloc byte[128], 128);
Wnaf.GetSignedVar(nb, 6, ws);
Wnaf.GetSignedVar(np, 4, ws2);
Wnaf.GetSignedVar(nq, 4, ws3);
int num = 4;
PointPrecompZ[] array = new PointPrecompZ[num];
PointPrecompZ[] array2 = new PointPrecompZ[num];
Init(out PointTemp r2);
PointPrecomputeZ(ref p, array, num, ref r2);
PointPrecomputeZ(ref q, array2, num, ref r2);
PointSetNeutral(ref r);
int num2 = 128;
while (--num2 >= 0 && (ws[num2] | ws[128 + num2] | ws2[num2] | ws3[num2]) == 0) {
}
while (num2 >= 0) {
int num3 = ws[num2];
if (num3 != 0) {
int num4 = (num3 >> 1) ^ (num3 >> 31);
PointAddVar(num3 < 0, ref PrecompBaseWnaf[num4], ref r, ref r2);
}
int num5 = ws[128 + num2];
if (num5 != 0) {
int num6 = (num5 >> 1) ^ (num5 >> 31);
PointAddVar(num5 < 0, ref PrecompBase128Wnaf[num6], ref r, ref r2);
}
int num7 = ws2[num2];
if (num7 != 0) {
int num8 = (num7 >> 1) ^ (num7 >> 31);
PointAddVar(num7 < 0, ref array[num8], ref r, ref r2);
}
int num9 = ws3[num2];
if (num9 != 0) {
int num10 = (num9 >> 1) ^ (num9 >> 31);
PointAddVar(num9 < 0, ref array2[num10], ref r, ref r2);
}
PointDouble(ref r);
num2--;
}
PointDouble(ref r);
PointDouble(ref r);
}
public static void Sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
byte[] ctx = null;
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[] m, int mOff, int mLen, byte[] sig, int sigOff)
{
byte[] ctx = null;
byte phflag = 0;
ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
}
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 Sign(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, null, 0, m, sig);
}
public static void Sign(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> pk, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, pk, null, 0, m, sig);
}
public static void Sign(ReadOnlySpan<byte> sk, byte[] ctx, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, ctx, 0, m, sig);
}
public static void Sign(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> pk, byte[] ctx, ReadOnlySpan<byte> m, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, pk, ctx, 0, m, sig);
}
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, IDigest ph, byte[] sig, int sigOff)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.DoFinal(array, 0))
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, IDigest ph, byte[] sig, int sigOff)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.DoFinal(array, 0))
throw new ArgumentException("ph");
byte phflag = 1;
ImplSign(sk, skOff, pk, pkOff, ctx, phflag, array, 0, array.Length, sig, sigOff);
}
public static void SignPrehash(ReadOnlySpan<byte> sk, byte[] ctx, ReadOnlySpan<byte> ph, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (ph.Length != PrehashSize)
throw new ArgumentException("ph");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, ctx, 1, ph, sig);
}
public static void SignPrehash(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> pk, byte[] ctx, ReadOnlySpan<byte> ph, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
if (ph.Length != PrehashSize)
throw new ArgumentException("ph");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
ImplSign(sk, pk, ctx, 1, ph, sig);
}
public unsafe static void SignPrehash(ReadOnlySpan<byte> sk, byte[] ctx, IDigest ph, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
int prehashSize = PrehashSize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)prehashSize], prehashSize);
if (PrehashSize != ph.DoFinal(span))
throw new ArgumentException("ph");
ImplSign(sk, ctx, 1, span, sig);
}
public unsafe static void SignPrehash(ReadOnlySpan<byte> sk, ReadOnlySpan<byte> pk, byte[] ctx, IDigest ph, Span<byte> sig)
{
if (sk.Length != SecretKeySize)
throw new ArgumentException("sk");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
int prehashSize = PrehashSize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)prehashSize], prehashSize);
if (PrehashSize != ph.DoFinal(span))
throw new ArgumentException("ph");
ImplSign(sk, pk, ctx, 1, span, sig);
}
public static bool ValidatePublicKeyFull(byte[] pk, int pkOff)
{
return ValidatePublicKeyFull(pk.AsSpan(pkOff));
}
public unsafe static bool ValidatePublicKeyFull(ReadOnlySpan<byte> pk)
{
int publicKeySize = PublicKeySize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)publicKeySize], publicKeySize);
span.CopyFrom(pk);
if (!CheckPointFullVar(span))
return false;
Init(out PointAffine r);
if (!DecodePointVar(span, false, ref r))
return false;
return CheckPointOrderVar(ref r);
}
public static PublicPoint ValidatePublicKeyFullExport(byte[] pk, int pkOff)
{
return ValidatePublicKeyFullExport(pk.AsSpan(pkOff));
}
public unsafe static PublicPoint ValidatePublicKeyFullExport(ReadOnlySpan<byte> pk)
{
int publicKeySize = PublicKeySize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)publicKeySize], publicKeySize);
span.CopyFrom(pk);
if (!CheckPointFullVar(span))
return null;
Init(out PointAffine r);
if (!DecodePointVar(span, false, ref r))
return null;
if (!CheckPointOrderVar(ref r))
return null;
return ExportPoint(ref r);
}
public static bool ValidatePublicKeyPartial(byte[] pk, int pkOff)
{
return ValidatePublicKeyPartial(pk.AsSpan(pkOff));
}
public unsafe static bool ValidatePublicKeyPartial(ReadOnlySpan<byte> pk)
{
int publicKeySize = PublicKeySize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)publicKeySize], publicKeySize);
span.CopyFrom(pk);
if (!CheckPointFullVar(span))
return false;
Init(out PointAffine r);
return DecodePointVar(span, false, ref r);
}
public static PublicPoint ValidatePublicKeyPartialExport(byte[] pk, int pkOff)
{
return ValidatePublicKeyPartialExport(pk.AsSpan(pkOff));
}
public unsafe static PublicPoint ValidatePublicKeyPartialExport(ReadOnlySpan<byte> pk)
{
int publicKeySize = PublicKeySize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)publicKeySize], publicKeySize);
span.CopyFrom(pk);
if (!CheckPointFullVar(span))
return null;
Init(out PointAffine r);
if (!DecodePointVar(span, false, ref r))
return null;
return ExportPoint(ref r);
}
public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen)
{
byte[] ctx = null;
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[] m, int mOff, int mLen)
{
byte[] ctx = null;
byte phflag = 0;
return ImplVerify(sig, sigOff, publicPoint, ctx, phflag, m, mOff, mLen);
}
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 Verify(ReadOnlySpan<byte> sig, ReadOnlySpan<byte> pk, ReadOnlySpan<byte> m)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
return ImplVerify(sig, pk, null, 0, m);
}
public static bool Verify(ReadOnlySpan<byte> sig, PublicPoint publicPoint, ReadOnlySpan<byte> m)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
return ImplVerify(sig, publicPoint, null, 0, m);
}
public static bool Verify(ReadOnlySpan<byte> sig, ReadOnlySpan<byte> pk, byte[] ctx, ReadOnlySpan<byte> m)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
return ImplVerify(sig, pk, ctx, 0, m);
}
public static bool Verify(ReadOnlySpan<byte> sig, PublicPoint publicPoint, byte[] ctx, ReadOnlySpan<byte> m)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
return ImplVerify(sig, publicPoint, ctx, 0, m);
}
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, IDigest ph)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.DoFinal(array, 0))
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, IDigest ph)
{
byte[] array = new byte[PrehashSize];
if (PrehashSize != ph.DoFinal(array, 0))
throw new ArgumentException("ph");
byte phflag = 1;
return ImplVerify(sig, sigOff, publicPoint, ctx, phflag, array, 0, array.Length);
}
public static bool VerifyPrehash(ReadOnlySpan<byte> sig, ReadOnlySpan<byte> pk, byte[] ctx, ReadOnlySpan<byte> ph)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
if (ph.Length != PrehashSize)
throw new ArgumentException("ph");
return ImplVerify(sig, pk, ctx, 1, ph);
}
public static bool VerifyPrehash(ReadOnlySpan<byte> sig, PublicPoint publicPoint, byte[] ctx, ReadOnlySpan<byte> ph)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
if (ph.Length != PrehashSize)
throw new ArgumentException("ph");
return ImplVerify(sig, publicPoint, ctx, 1, ph);
}
public unsafe static bool VerifyPrehash(ReadOnlySpan<byte> sig, ReadOnlySpan<byte> pk, byte[] ctx, IDigest ph)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
if (pk.Length != PublicKeySize)
throw new ArgumentException("pk");
int prehashSize = PrehashSize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)prehashSize], prehashSize);
if (PrehashSize != ph.DoFinal(span))
throw new ArgumentException("ph");
return ImplVerify(sig, pk, ctx, 1, span);
}
public unsafe static bool VerifyPrehash(ReadOnlySpan<byte> sig, PublicPoint publicPoint, byte[] ctx, IDigest ph)
{
if (sig.Length != SignatureSize)
throw new ArgumentException("sig");
int prehashSize = PrehashSize;
Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)prehashSize], prehashSize);
if (PrehashSize != ph.DoFinal(span))
throw new ArgumentException("ph");
return ImplVerify(sig, publicPoint, ctx, 1, span);
}
}
}