frostfs-sdk-csharp/src/FrostFS.SDK.Cryptography/Tz/SL2.cs
Ivan Pchelintsev 11eff4e23e [#1] Move files to top level directory
Signed-off-by: Ivan Pchelintsev <i.pchelintsev@yadro.com>
2024-05-22 14:29:20 +03:00

177 lines
6.5 KiB
C#

namespace FrostFS.SDK.Cryptography.Tz
{
public class SL2 : IEquatable<SL2>
{
// 2x2 matrix
private readonly GF127[][] data;
public static readonly SL2 ID = new(new GF127(1, 0), new GF127(0, 0),
new GF127(0, 0), new GF127(1, 0));
public static readonly SL2 A = new(new GF127(2, 0), new GF127(1, 0),
new GF127(1, 0), new GF127(0, 0));
public static readonly SL2 B = new(new GF127(2, 0), new GF127(3, 0),
new GF127(1, 0), new GF127(1, 0));
// Indexer
public GF127[] this[int i]
{
get { return data[i]; }
set { data[i] = value; }
}
public SL2(GF127[][] value)
{
if (value is null || value.Length != 2 || !value.All(p => p.Length == 2))
throw new ArgumentException(nameof(value) + $" invalid {nameof(GF127)} matrics");
data = value;
}
public SL2(GF127 g00, GF127 g01, GF127 g10, GF127 g11)
: this(new GF127[][] { new[] { g00, g01 }, new[] { g10, g11 } })
{
}
public SL2() : this(GF127.One, GF127.Zero, GF127.Zero, GF127.One)
{
}
public override bool Equals(object obj)
{
if (obj is null)
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj is SL2 b)
return Equals(b);
return false;
}
public override int GetHashCode()
{
return this[0][0].GetHashCode() +
this[0][1].GetHashCode() +
this[1][0].GetHashCode() +
this[1][1].GetHashCode();
}
public bool Equals(SL2 other)
{
if (other is null)
return false;
if (ReferenceEquals(this, other))
return true;
return this[0][0].Equals(other[0][0]) &&
this[0][1].Equals(other[0][1]) &&
this[1][0].Equals(other[1][0]) &&
this[1][1].Equals(other[1][1]);
}
// 2X2 matrix multiplication
public static SL2 operator *(SL2 a, SL2 b)
{
return new SL2(a[0][0] * b[0][0] + a[0][1] * b[1][0], a[0][0] * b[0][1] + a[0][1] * b[1][1],
a[1][0] * b[0][0] + a[1][1] * b[1][0], a[1][0] * b[0][1] + a[1][1] * b[1][1]);
}
// Multiplication using strassen algorithm
public static SL2 MulStrassen(SL2 a, SL2 b)
{
GF127[] t = new GF127[7];
t[0] = (a[0][0] + a[1][1]) * (b[0][0] + b[1][1]); // t[0] == (a11 + a22) * (b11 + b22)
t[1] = (a[1][0] + a[1][1]) * b[0][0]; // t[1] == (a21 + a22) * b11
t[2] = (b[0][1] + b[1][1]) * a[0][0]; // t[2] == (b12 + b22) * a11
t[3] = (b[1][0] + b[0][0]) * a[1][1]; // t[3] == (b21 + b11) * a22
t[4] = (a[0][0] + a[0][1]) * b[1][1]; // t[4] == (a11 + a12) * b22
t[5] = (a[1][0] + a[0][0]) * (b[0][0] + b[0][1]); // t[5] == (a21 + a11) * (b11 + b12)
t[6] = (a[0][1] + a[1][1]) * (b[1][0] + b[1][1]); // t[6] == (a12 + a22) * (b21 + b22)
SL2 r = new();
r[0][1] = t[2] + t[4]; // r12 == a11*b12 + a11*b22 + a11*b22 + a12*b22 == a11*b12 + a12*b22
r[1][0] = t[1] + t[3]; // r21 == a21*b11 + a22*b11 + a22*b21 + a22*b11 == a21*b11 + a22*b21
// r11 == (a11*b11 + a22*b11` + a11*b22` + a22*b22`) + (a22*b21` + a22*b11`) + (a11*b22` + a12*b22`) +
// (a12*b21 + a22*b21` + a12*b22` + a22*b22`) == a11*b11 + a12*b21
r[0][0] = t[0] + t[3] + t[4] + t[6];
// r22 == (a11*b11` + a22*b11` + a11*b22` + a22*b22) + (a21*b11` + a22*b11`) + (a11*b12` + a11*b22`) +
// (a21*b11` + a11*b11` + a21*b12 + a11*b12`) == a21*b12 + a22*b22
r[1][1] = t[0] + t[1] + t[2] + t[5];
return r;
}
// Inv() returns inverse of a in SL2(GF(2^127))
public static SL2 Inv(SL2 a)
{
GF127[] t = new GF127[2];
t[0] = a[0][0] * a[1][1] + a[0][1] * a[1][0]; //
t[1] = GF127.Inv(t[0]);
SL2 r = new();
r[1][1] = t[1] * a[0][0];
r[0][1] = t[1] * a[0][1];
r[1][0] = t[1] * a[1][0];
r[0][0] = t[1] * a[1][1];
return r;
}
// MulA() returns this*A, A = {{x, 1}, {1, 0}}
public SL2 MulA()
{
var r = new SL2();
r[0][0] = GF127.Mul10(this[0][0]) + this[0][1]; // r11 == t11*x + t12
r[0][1] = this[0][0]; // r12 == t11
r[1][0] = GF127.Mul10(this[1][0]) + this[1][1]; // r21 == t21*x + t22
r[1][1] = this[1][0]; // r22 == t21
return r;
}
// MulB() returns this*B, B = {{x, x+1}, {1, 1}}
public SL2 MulB()
{
var r = new SL2();
r[0][0] = GF127.Mul10(this[0][0]) + this[0][1]; // r11 == t11*x + t12
r[0][1] = GF127.Mul10(this[0][0]) + this[0][0] + this[0][1]; // r12 == t11*x + t11 + t12
r[1][0] = GF127.Mul10(this[1][0]) + this[1][1]; // r21 == t21*x + t22
r[1][1] = GF127.Mul10(this[1][0]) + this[1][0] + this[1][1]; // r22 == t21*x + t21 + t22
return r;
}
public SL2 FromByteArray(byte[] data)
{
if (data.Length != 64)
throw new ArgumentException(nameof(SL2) + $" invalid data, exect={64}, ecatual={data.Length}");
this[0][0] = new GF127().FromByteArray(data[0..16]);
this[0][1] = new GF127().FromByteArray(data[16..32]);
this[1][0] = new GF127().FromByteArray(data[32..48]);
this[1][1] = new GF127().FromByteArray(data[48..64]);
return this;
}
public byte[] ToByteArray()
{
var buff = new byte[64];
Array.Copy(this[0][0].ToByteArray(), 0, buff, 0, 16);
Array.Copy(this[0][1].ToByteArray(), 0, buff, 16, 16);
Array.Copy(this[1][0].ToByteArray(), 0, buff, 32, 16);
Array.Copy(this[1][1].ToByteArray(), 0, buff, 48, 16);
return buff;
}
public override string ToString()
{
return this[0][0].ToString() + this[0][1].ToString() +
this[1][0].ToString() + this[1][1].ToString();
}
}
}