Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmpa committed Nov 8, 2024
2 parents 5da1a37 + 52f21d0 commit 19d98d7
Show file tree
Hide file tree
Showing 25 changed files with 1,047 additions and 304 deletions.
17 changes: 17 additions & 0 deletions Assets/Neo2Legacy/Core/NeoKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ public NeoKeys(byte[] privateKey)
this.WIF = GetWIF();
}

public static string PublicKeyToN2Address(byte[] publicKey)
{
byte[] compressedPublicKey;
if(publicKey.Length == 33) // Compressed
{
compressedPublicKey = publicKey;
}
else
{
compressedPublicKey = ECDsa.CompressPublicKey(publicKey);
}

var signatureScriptN2 = CreateSignatureScript(compressedPublicKey);
var signatureHashN2 = NeoUtils.ToScriptHash(signatureScriptN2);
return NeoUtils.ToAddress(signatureHashN2);
}

public static NeoKeys FromWIF(string wif)
{
if (wif == null) throw new ArgumentNullException();
Expand Down
29 changes: 29 additions & 0 deletions Assets/Phantasma.SDK/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,35 @@ public static void Write(string message, Level level = Level.Logic, UnityDebugLo
}
}

#if UNITY_5_3_OR_NEWER
switch (unityDebugLogMode)
{
case UnityDebugLogMode.Normal:
Debug.Log(message);
break;
case UnityDebugLogMode.Warning:
Debug.LogWarning(message);
break;
case UnityDebugLogMode.Error:
Debug.LogError(message);
break;
}
#endif
}

public static void WriteRaw(string message, Level level = Level.Logic, UnityDebugLogMode unityDebugLogMode = UnityDebugLogMode.Normal)
{
if (LogStreamWriter != null && MaxLevel != Level.Disabled && level <= MaxLevel)
{
lock (Locker)
{
if (ConsoleOutput)
Console.Write(message);
LogStreamWriter.Write(message);
LogStreamWriter.Flush();
}
}

#if UNITY_5_3_OR_NEWER
switch (unityDebugLogMode)
{
Expand Down
17 changes: 16 additions & 1 deletion Assets/Phantasma/Phantasma.Business/src/VM/Utils/DisasmUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Phantasma.Core;
using Phantasma.Core.Domain;

namespace Phantasma.Business.VM.Utils
Expand Down Expand Up @@ -133,7 +134,8 @@ public static IEnumerable<string> ExtractContractNames(Disassembler disassembler
var result = new List<string>();

int index = 0;
var regs = new VMObject[16];
var regsLength = 16;
var regs = new VMObject[regsLength];
while (index < instructions.Length)
{
var instruction = instructions[index];
Expand All @@ -142,10 +144,14 @@ public static IEnumerable<string> ExtractContractNames(Disassembler disassembler
{
case Opcode.LOAD:
{
Throw.If(instruction.Args.Length < 3, $"Opcode.LOAD: instruction.Args length {instruction.Args.Length} is less than {3}");

var dst = (byte)instruction.Args[0];
var type = (VMType)instruction.Args[1];
var bytes = (byte[])instruction.Args[2];

Throw.If(dst >= regsLength, $"Opcode.LOAD: Destination {dst} is out of range 0-{regsLength - 1}");

regs[dst] = new VMObject();
regs[dst].SetValue(bytes, type);

Expand All @@ -154,18 +160,27 @@ public static IEnumerable<string> ExtractContractNames(Disassembler disassembler

case Opcode.CTX:
{
Throw.If(instruction.Args.Length < 2, $"Opcode.CTX: instruction.Args length {instruction.Args.Length} is less than {2}");

var src = (byte)instruction.Args[0];
var dst = (byte)instruction.Args[1];

Throw.If(src >= regsLength, $"Opcode.CTX: Source {src} is out of range 0-{regsLength - 1}");
Throw.If(dst >= regsLength, $"Opcode.CTX: Destination {dst} is out of range 0-{regsLength - 1}");

regs[dst] = new VMObject();
regs[dst].Copy(regs[src]);
break;
}

case Opcode.SWITCH:
{
Throw.If(instruction.Args.Length < 1, $"Opcode.SWITCH: instruction.Args length {instruction.Args.Length} is less than {1}");

var src = (byte)instruction.Args[0];

Throw.If(src >= regsLength, $"Opcode.SWITCH: Source {src} is out of range 0-{regsLength - 1}");

var contractName = regs[src].AsString();
result.Add(contractName);
break;
Expand Down
15 changes: 15 additions & 0 deletions Assets/Phantasma/Phantasma.Core/src/Cryptography/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,21 @@ public byte[] ToByteArray()
return bytes;
}

public byte[] GetPublicKey()
{
var bytes = new byte[32];
if (_bytes != null)
{
if (_bytes.Length != LengthInBytes)
{
throw new Exception("invalid address byte length");
}
ByteArrayUtils.CopyBytes(_bytes, 2, bytes, 0, _bytes.Length - 2);
}

return bytes;
}

public int CompareTo(Address other)
{
byte[] x = ToByteArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Phantasma.Core.Cryptography.Hashing;
using Phantasma.Core.Numerics;
using Phantasma.Core.Utils;
using SHA256 = System.Security.Cryptography.SHA256;

namespace Phantasma.Core.Cryptography
{
public static class CryptoExtensions
{
private static ThreadLocal<SHA256> _sha256 = new ThreadLocal<SHA256>(() => SHA256.Create());

public static byte[] AESGenerateIV(int vectorSize)
{
var ivBytes = new byte[vectorSize];
Expand Down Expand Up @@ -69,16 +64,6 @@ public static string Base58CheckEncode(this byte[] data)
return Base58.Encode(buffer);
}

public static byte[] Sha256(this IEnumerable<byte> value)
{
return _sha256.Value.ComputeHash(value.ToArray());
}

public static byte[] Sha256(this byte[] value, int offset, int count)
{
return _sha256.Value.ComputeHash(value, offset, count);
}

public static byte[] Sha256(this string value)
{
var bytes = Encoding.UTF8.GetBytes(value);
Expand All @@ -87,12 +72,12 @@ public static byte[] Sha256(this string value)

public static byte[] Sha256(this byte[] value)
{
return new Hashing.SHA256().ComputeHash(value, 0, (uint)value.Length);
return Hashing.SHA256.ComputeHash(value, 0, (uint)value.Length);
}

public static byte[] Sha256(this byte[] value, uint offset, uint count)
{
return new Hashing.SHA256().ComputeHash(value, offset, count);
return Hashing.SHA256.ComputeHash(value, offset, count);
}
}
}
147 changes: 62 additions & 85 deletions Assets/Phantasma/Phantasma.Core/src/Cryptography/ECDsa/ECDsa.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using System.Linq;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Poltergeist.PhantasmaLegacy.Ethereum.Hex.HexConvertors.Extensions;

namespace Phantasma.Core.Cryptography.ECDsa
{
Expand All @@ -20,117 +18,96 @@ public static class ECDsa
{
public static byte[] GetPublicKey(byte[] privateKey, bool compressed, ECDsaCurve curve)
{
X9ECParameters ecCurve;
switch (curve)
{
case ECDsaCurve.Secp256k1:
ecCurve = SecNamedCurves.GetByName("secp256k1");
break;
default:
ecCurve = SecNamedCurves.GetByName("secp256r1");
break;
}

var dom = new ECDomainParameters(ecCurve.Curve, ecCurve.G, ecCurve.N, ecCurve.H);
var dom = ECDsaHelpers.GetECDomainParameters(curve);

var d = new BigInteger(1, privateKey);
var q = dom.G.Multiply(d);


var publicParams = new ECPublicKeyParameters(q, dom);
return publicParams.Q.GetEncoded(compressed);
}
public static ECDomainParameters GetDomain(ECDsaCurve curve)

public static byte[] CompressPublicKey(byte[] uncompressedPublicKey)
{
X9ECParameters ecCurve;
switch (curve)
var x = new BigInteger(1, uncompressedPublicKey.Take(32).ToArray());
var y = new BigInteger(1, uncompressedPublicKey.Skip(32).ToArray());

byte prefix = 0x02;
if (y.Mod(BigInteger.Two) != BigInteger.Zero)
{
case ECDsaCurve.Secp256k1:
ecCurve = SecNamedCurves.GetByName("secp256k1");
break;
default:
ecCurve = SecNamedCurves.GetByName("secp256r1");
break;
prefix = 0x03;
}

return new ECDomainParameters(ecCurve.Curve, ecCurve.G, ecCurve.N, ecCurve.H);
return new byte[] { prefix }.Concat(x.ToByteArrayUnsigned()).ToArray();
}

public static byte[] Sign(byte[] message, byte[] prikey, ECDsaCurve curve)
public static byte[] DecompressPublicKey(byte[] compressedPublicKey, ECDsaCurve curve, bool dropUncompressedKeyPrefixByte = false)
{
var signer = SignerUtilities.GetSigner("SHA256withECDSA");
X9ECParameters ecCurve;
switch (curve)
if (compressedPublicKey.Length != 33)
{
case ECDsaCurve.Secp256k1:
ecCurve = SecNamedCurves.GetByName("secp256k1");
break;
default:
ecCurve = SecNamedCurves.GetByName("secp256r1");
break;
throw new ArgumentException("Incorrect compressed key length: " + compressedPublicKey.Length);
}
var dom = new ECDomainParameters(ecCurve.Curve, ecCurve.G, ecCurve.N, ecCurve.H);
var privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(1, prikey), dom);

signer.Init(true, privateKeyParameters);
signer.BlockUpdate(message, 0, message.Length);
var signature = signer.GenerateSignature();
var publicKeyParameters = ECDsaHelpers.GetECPublicKeyParameters(curve, compressedPublicKey);

return FromDER(signature);
}
var uncompressedPublicKey = publicKeyParameters.Q.GetEncoded(false);

public static bool Verify(byte[] message, byte[] signature, byte[] pubkey, ECDsaCurve curve)
{
var signer = SignerUtilities.GetSigner("SHA256withECDSA");
X9ECParameters ecCurve;
switch (curve)
if (dropUncompressedKeyPrefixByte)
{
case ECDsaCurve.Secp256k1:
ecCurve = SecNamedCurves.GetByName("secp256k1");
break;
default:
ecCurve = SecNamedCurves.GetByName("secp256r1");
break;
uncompressedPublicKey = uncompressedPublicKey.Skip(1).ToArray();
}
var dom = new ECDomainParameters(ecCurve.Curve, ecCurve.G, ecCurve.N, ecCurve.H);

ECPublicKeyParameters publicKeyParameters;
if (pubkey.Length == 33)
publicKeyParameters = new ECPublicKeyParameters(dom.Curve.DecodePoint(pubkey), dom);
else
publicKeyParameters = new ECPublicKeyParameters(dom.Curve.CreatePoint(new BigInteger(1, pubkey.Take(pubkey.Length / 2).ToArray()), new BigInteger(1, pubkey.Skip(pubkey.Length / 2).ToArray())), dom);
return uncompressedPublicKey;
}

signer.Init(false, publicKeyParameters);
public static byte[] Sign(byte[] message, byte[] prikey, ECDsaCurve curve)
{
var signer = SignerUtilities.GetSigner("SHA256withECDSA");
var privateKeyParameters = ECDsaHelpers.GetECPrivateKeyParameters(curve, prikey);

signer.Init(true, privateKeyParameters);
signer.BlockUpdate(message, 0, message.Length);
var signature = signer.GenerateSignature();

return ECDsaHelpers.FromDER(signature);
}

return signer.VerifySignature(ToDER(signature));
private static byte[] ByteArrayLeftPad(byte[] sourceArray, byte padValue, int len)
{
if(sourceArray.Length == len)
return sourceArray;

var prefixArray = Enumerable.Repeat(padValue, len - sourceArray.Length).ToArray();
return prefixArray.Concat(sourceArray).ToArray();
}

public static byte[] FromDER(byte[] signature)
public static byte[] SignDeterministic(byte[] message, byte[] prikey, ECDsaCurve curve)
{
using var decoder = new Asn1InputStream(signature);
var seq = decoder.ReadObject() as DerSequence;
if (seq == null || seq.Count != 2)
throw new FormatException("Invalid DER Signature");
var R = ((DerInteger)seq[0]).Value.ToByteArrayUnsigned();
var S = ((DerInteger)seq[1]).Value.ToByteArrayUnsigned();

byte[] concatenated = new byte[R.Length + S.Length];
Buffer.BlockCopy(R, 0, concatenated, 0, R.Length);
Buffer.BlockCopy(S, 0, concatenated, R.Length, S.Length);

return concatenated;
var messageHash = Hashing.SHA256.ComputeHash(message);

var privateKeyParameters = ECDsaHelpers.GetECPrivateKeyParameters(curve, prikey);

var signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));

signer.Init(true, privateKeyParameters);

var RS = signer.GenerateSignature(messageHash);
var R = ByteArrayLeftPad(RS[0].ToByteArrayUnsigned(), 0, 32);
var S = ByteArrayLeftPad(RS[1].ToByteArrayUnsigned(), 0, 32);

return R.Concat(S).ToArray();
}
public static byte[] ToDER(byte[] signature)

public static bool Verify(byte[] message, byte[] signature, byte[] pubkey, ECDsaCurve curve)
{
// We convert from concatenated "raw" R + S format to DER format that Bouncy Castle uses.
return new DerSequence(
// first 32 bytes is "R" number
new DerInteger(new BigInteger(1, signature.Take(32).ToArray())),
// last 32 bytes is "S" number
new DerInteger(new BigInteger(1, signature.Skip(32).ToArray())))
.GetDerEncoded();
var signer = SignerUtilities.GetSigner("SHA256withECDSA");
var publicKeyParameters = ECDsaHelpers.GetECPublicKeyParameters(curve, pubkey);

signer.Init(false, publicKeyParameters);
signer.BlockUpdate(message, 0, message.Length);

return signer.VerifySignature(ECDsaHelpers.ToDER(signature));
}
}
}
Loading

0 comments on commit 19d98d7

Please sign in to comment.