Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add random number to neo #2477

Merged
merged 65 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b3680dc
Add Verifiable Random Function and test cases
Jim8y May 16, 2021
6579546
update the code format.
Jim8y May 16, 2021
192e553
Merge branch 'master' into master
shargon May 16, 2021
bcb863a
Remove empty lines
shargon May 17, 2021
a525e77
Remove empty lines
shargon May 17, 2021
7b99fad
fix TODO by throwing exception
Jim8y May 17, 2021
e47e565
Merge branch 'master' of github.com:Liaojinghui/neo
Jim8y May 17, 2021
1391184
add a `nonce` field to the header
Jim8y May 18, 2021
80fff9d
Add comment to GetRandom
Jim8y May 18, 2021
cc1b9f7
update comment
Jim8y May 18, 2021
1b2f912
change pubkey type to ECPoint
Jim8y May 18, 2021
10e7b6d
Add exception
Jim8y May 20, 2021
4ecdc48
Remove VRF from neo core to dBFT plugin
Jim8y May 21, 2021
d8f2bb2
Remove empty line
erikzhang May 22, 2021
d20bd0d
add suppoort to multiple random numbers
Jim8y May 22, 2021
110db72
update test
Jim8y May 22, 2021
0126393
Add extra random check
Jim8y May 22, 2021
bb3e29d
fix mistake
Jim8y May 22, 2021
cd23177
update random algorithm
Jim8y May 22, 2021
d58a3ce
Clean code
shargon May 23, 2021
99fa4b7
Add extra check to next_nonce
Jim8y May 23, 2021
5ed2940
fix error
Jim8y May 23, 2021
f52c2b2
Add more test to test random number
Jim8y May 23, 2021
60086e3
Add extra check to make sure the next_once will be reinitialized when…
Jim8y May 23, 2021
798cafc
Variable name style consistency
Jim8y May 23, 2021
91a8836
Remove `nonce` from the header.
Jim8y May 24, 2021
6a1ba3d
update test
Jim8y May 24, 2021
11ba5b7
fix test error. So weird the error does not exist in my local environ…
Jim8y May 24, 2021
1ba655f
get the nonce_tx at index 0
Jim8y May 27, 2021
9470311
Set next_nonce to null if there is no valid getrandom call in the per…
Jim8y May 27, 2021
728f479
update runtime test
Jim8y May 27, 2021
62eda32
Set the ECCurve.N public since VRFin the dBFT need to use this value.
Jim8y May 30, 2021
a0ee63e
Merge branch 'master' into vrf
shargon May 31, 2021
e62b56b
add nonce to header
Jim8y Jun 8, 2021
303bbbb
nextnonce : ulong to replace byte[]
Jim8y Jun 8, 2021
e5aa633
format
erikzhang Jun 9, 2021
d0c81f7
add nonce to `trimmedblock`
Jim8y Jun 9, 2021
c48adbc
Merge branch 'vrf' of https://github.com/Liaojinghui/neo into vrf
Jim8y Jun 9, 2021
491df4a
update comment
Jim8y Jun 9, 2021
2cec716
add `Murmur128`
Jim8y Jun 9, 2021
73b989c
add more test to `Murmur128`
Jim8y Jun 9, 2021
3087243
fix format
Jim8y Jun 9, 2021
e43c150
`ulong` to `hexstring` in `ToJson`
Jim8y Jun 9, 2021
714bac5
update nonce.
Jim8y Jun 10, 2021
3d3d3ed
update format
Jim8y Jun 10, 2021
4a508ae
update `getrandom`
Jim8y Jun 10, 2021
9359dff
update comment
Jim8y Jun 10, 2021
4360d00
Update src/neo/Network/P2P/Payloads/Header.cs
Jim8y Jun 11, 2021
8a059bb
update unite test
Jim8y Jun 11, 2021
2fab87f
Update src/neo/Network/P2P/Payloads/Header.cs
Jim8y Jun 11, 2021
866ffe4
update test
Jim8y Jun 11, 2021
bcd6b27
Merge branch 'vrf' of https://github.com/Liaojinghui/neo into vrf
Jim8y Jun 11, 2021
874e633
Merge branch 'master' into vrf
Qiao-Jin Jun 23, 2021
f5b3bf1
Update `GetRandom`
Jim8y Jun 24, 2021
1ca4244
update comments
Jim8y Jun 24, 2021
8f89321
update comments and format
Jim8y Jun 24, 2021
654e37b
Improve
erikzhang Jun 25, 2021
5258a1b
More improve
erikzhang Jun 25, 2021
ef41ef2
Fix UT
erikzhang Jun 25, 2021
daa642b
update `nonce` test cases
Jim8y Jun 25, 2021
ac35197
Merge branch 'vrf' of https://github.com/Liaojinghui/neo into vrf
Jim8y Jun 25, 2021
460f0a6
update comments
Jim8y Jun 26, 2021
77c7775
Format UT
shargon Jun 28, 2021
2c6be15
Merge branch 'master' into vrf
shargon Jun 29, 2021
30f33d0
Merge branch 'master' into vrf
erikzhang Jun 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/neo/Cryptography/ECC/ECCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ECCurve
internal readonly BigInteger Q;
internal readonly ECFieldElement A;
internal readonly ECFieldElement B;
internal readonly BigInteger N;
public readonly BigInteger N;
/// <summary>
/// The point at infinity.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions src/neo/Cryptography/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ public static uint Murmur32(this byte[] value, uint seed)
return BinaryPrimitives.ReadUInt32LittleEndian(murmur.ComputeHash(value));
}

/// <summary>
/// Computes the 128-bit hash value for the specified byte array using the murmur algorithm.
/// </summary>
/// <param name="value">The input to compute the hash code for.</param>
/// <param name="seed">The seed used by the murmur algorithm.</param>
/// <returns>The computed hash code.</returns>
public static byte[] Murmur128(this byte[] value, uint seed)
{
using Murmur128 murmur = new(seed);
return murmur.ComputeHash(value);
}

/// <summary>
/// Computes the hash value for the specified byte array using the sha256 algorithm.
/// </summary>
Expand Down
135 changes: 135 additions & 0 deletions src/neo/Cryptography/Murmur128.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

namespace Neo.Cryptography
{
/// <summary>
/// Computes the 128 bits murmur hash for the input data.
/// </summary>
public sealed class Murmur128 : HashAlgorithm
{
private const ulong c1 = 0x87c37b91114253d5;
private const ulong c2 = 0x4cf5ad432745937f;
private const int r1 = 31;
private const int r2 = 33;
private const uint m = 5;
private const uint n1 = 0x52dce729;
private const uint n2 = 0x38495ab5;

private readonly uint seed;
private int length;

public override int HashSize => 128;

private ulong H1 { get; set; }
private ulong H2 { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="Murmur128"/> class with the specified seed.
/// </summary>
/// <param name="seed">The seed to be used.</param>
public Murmur128(uint seed)
{
this.seed = seed;
Initialize();
}

protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
length += cbSize;
int remainder = cbSize & 15;
int alignedLength = ibStart + (cbSize - remainder);
for (int i = ibStart; i < alignedLength; i += 16)
{
ulong k1 = BinaryPrimitives.ReadUInt64BigEndian(array.AsSpan(i));
k1 *= c1;
k1 = RotateLeft(k1, r1);
k1 *= c2;
H1 ^= k1;
H1 = RotateLeft(H1, 27);
H1 += H2;
H1 = H1 * m + n1;

ulong k2 = BinaryPrimitives.ReadUInt64BigEndian(array.AsSpan(i + 8));
k2 *= c2;
k2 = RotateLeft(k2, r2);
k2 *= c1;
H2 ^= k2;
H2 = RotateLeft(H2, 31);
H2 += H1;
H2 = H2 * m + n2;
}

if (remainder > 0)
{
ulong remainingBytesL = 0, remainingBytesH = 0;
switch (remainder)
{
case 15: remainingBytesH ^= (ulong)array[alignedLength + 14] << 48; goto case 14;
case 14: remainingBytesH ^= (ulong)array[alignedLength + 13] << 40; goto case 13;
case 13: remainingBytesH ^= (ulong)array[alignedLength + 12] << 32; goto case 12;
case 12: remainingBytesH ^= (ulong)array[alignedLength + 11] << 24; goto case 11;
case 11: remainingBytesH ^= (ulong)array[alignedLength + 10] << 16; goto case 10;
case 10: remainingBytesH ^= (ulong)array[alignedLength + 9] << 8; goto case 9;
case 9: remainingBytesH ^= (ulong)array[alignedLength + 8] << 0; goto case 8;
case 8: remainingBytesL ^= (ulong)array[alignedLength + 7] << 56; goto case 7;
case 7: remainingBytesL ^= (ulong)array[alignedLength + 6] << 48; goto case 6;
case 6: remainingBytesL ^= (ulong)array[alignedLength + 5] << 40; goto case 5;
case 5: remainingBytesL ^= (ulong)array[alignedLength + 4] << 32; goto case 4;
case 4: remainingBytesL ^= (ulong)array[alignedLength + 3] << 24; goto case 3;
case 3: remainingBytesL ^= (ulong)array[alignedLength + 2] << 16; goto case 2;
case 2: remainingBytesL ^= (ulong)array[alignedLength + 1] << 8; goto case 1;
case 1: remainingBytesL ^= (ulong)array[alignedLength] << 0; break;
}

H2 ^= RotateLeft(remainingBytesH * c2, r2) * c1;
H1 ^= RotateLeft(remainingBytesL * c1, r1) * c2;
}
}

protected override byte[] HashFinal()
{
ulong len = (ulong)length;
H1 ^= len; H2 ^= len;

H1 += H2;
H2 += H1;

H1 = FMix(H1);
H2 = FMix(H2);

H1 += H2;
H2 += H1;

var buffer = new byte[16];
Array.Copy(BitConverter.GetBytes(H1), 0, buffer, 0, 8);
Array.Copy(BitConverter.GetBytes(H2), 0, buffer, 8, 8);

return buffer;
}

public override void Initialize()
{
H1 = H2 = seed;
length = 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong RotateLeft(ulong x, byte n)
{
return (x << n) | (x >> (64 - n));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong FMix(ulong h)
{
// pipelining friendly algorithm
h = (h ^ (h >> 33)) * 0xff51afd7ed558ccd;
h = (h ^ (h >> 33)) * 0xc4ceb9fe1a85ec53;

return (h ^ (h >> 33));
}
}
}
1 change: 1 addition & 0 deletions src/neo/NeoSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public NeoSystem(ProtocolSettings settings, string storageEngine = null, string
PrevHash = UInt256.Zero,
MerkleRoot = UInt256.Zero,
Timestamp = (new DateTime(2016, 7, 15, 15, 8, 21, DateTimeKind.Utc)).ToTimestampMS(),
Nonce = 2083236893, // nonce from the Bitcoin genesis block.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any meaning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any meaning?

nop, we dont really need any meaningful nonce here, it is just a placeholder, so i picked the nonce from the bitcoin genesis block to show our respect to Satoshi Nakamoto.

Index = 0,
PrimaryIndex = 0,
NextConsensus = Contract.GetBFTAddress(settings.StandbyValidators),
Expand Down
5 changes: 5 additions & 0 deletions src/neo/Network/P2P/Payloads/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public sealed class Block : IEquatable<Block>, IInventory
/// </summary>
public ulong Timestamp => Header.Timestamp;

/// <summary>
/// The random number of the block from VRF.
/// </summary>
public ulong Nonce => Header.Nonce;

/// <summary>
/// The index of the block.
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions src/neo/Network/P2P/Payloads/Header.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public sealed class Header : IEquatable<Header>, IVerifiable
private UInt256 prevHash;
private UInt256 merkleRoot;
private ulong timestamp;
private ulong nonce;
private uint index;
private byte primaryIndex;
private UInt160 nextConsensus;
Expand Down Expand Up @@ -64,6 +65,15 @@ public ulong Timestamp
set { timestamp = value; _hash = null; }
}

/// <summary>
/// The first eight bytes of random number generated from VRF.
/// </summary>
public ulong Nonce
{
get => nonce;
set { nonce = value; _hash = null; }
}

/// <summary>
/// The index of the block.
/// </summary>
Expand Down Expand Up @@ -109,6 +119,7 @@ public UInt256 Hash
UInt256.Length + // PrevHash
UInt256.Length + // MerkleRoot
sizeof(ulong) + // Timestamp
sizeof(ulong) + // Nonce
sizeof(uint) + // Index
sizeof(byte) + // PrimaryIndex
UInt160.Length + // NextConsensus
Expand Down Expand Up @@ -143,6 +154,7 @@ void IVerifiable.DeserializeUnsigned(BinaryReader reader)
prevHash = reader.ReadSerializable<UInt256>();
merkleRoot = reader.ReadSerializable<UInt256>();
timestamp = reader.ReadUInt64();
nonce = reader.ReadUInt64();
index = reader.ReadUInt32();
primaryIndex = reader.ReadByte();
nextConsensus = reader.ReadSerializable<UInt160>();
Expand Down Expand Up @@ -185,6 +197,7 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer)
writer.Write(prevHash);
writer.Write(merkleRoot);
writer.Write(timestamp);
writer.Write(nonce);
writer.Write(index);
writer.Write(primaryIndex);
writer.Write(nextConsensus);
Expand All @@ -204,6 +217,7 @@ public JObject ToJson(ProtocolSettings settings)
json["previousblockhash"] = prevHash.ToString();
json["merkleroot"] = merkleRoot.ToString();
json["time"] = timestamp;
json["nonce"] = nonce.ToString("X16");
json["index"] = index;
json["primary"] = primaryIndex;
json["nextconsensus"] = nextConsensus.ToAddress(settings.AddressVersion);
Expand Down
23 changes: 23 additions & 0 deletions src/neo/SmartContract/ApplicationEngine.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ partial class ApplicationEngine
/// </summary>
public static readonly InteropDescriptor System_Runtime_GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", nameof(GetInvocationCounter), 1 << 4, CallFlags.None);

/// <summary>
/// The <see cref="InteropDescriptor"/> of System.Runtime.GetRandom.
/// Gets the random number generated from the VRF.
/// </summary>
public static readonly InteropDescriptor System_Runtime_GetRandom = Register("System.Runtime.GetRandom", nameof(GetRandom), 1 << 4, CallFlags.None);
erikzhang marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The <see cref="InteropDescriptor"/> of System.Runtime.Log.
/// Writes a log.
Expand Down Expand Up @@ -228,6 +234,23 @@ protected internal int GetInvocationCounter()
return counter;
}

/// <summary>
/// The implementation of System.Runtime.GetRandom.
/// Gets the random number, random number will xor with the hash value of the transaction.
/// </summary>
/// <returns>The first eight bytes of the random number.</returns>
protected internal ulong GetRandom()
{
// Return 0 if here is no persistingBlock.
// We need this for users to test their transactions locally.
if (nextNonce == 0) return 0;
var nonce = nextNonce;
nextNonce = BitConverter.ToUInt64(Cryptography.Helper.Murmur128(BitConverter.GetBytes(nonce), 123)[..8]);
var tx = (Transaction)ScriptContainer;

return nonce ^ BitConverter.ToUInt64(tx?.Hash.ToArray());
}

/// <summary>
/// The implementation of System.Runtime.Log.
/// Writes a log.
Expand Down
11 changes: 11 additions & 0 deletions src/neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ public partial class ApplicationEngine : ExecutionEngine
/// </summary>
public IReadOnlyList<NotifyEventArgs> Notifications => notifications ?? (IReadOnlyList<NotifyEventArgs>)Array.Empty<NotifyEventArgs>();

/// <summary>
/// The nonce seed for the next random call.
/// </summary>
private ulong nextNonce;


/// <summary>
/// Initializes a new instance of the <see cref="ApplicationEngine"/> class.
/// </summary>
Expand All @@ -134,6 +140,11 @@ protected ApplicationEngine(TriggerType trigger, IVerifiable container, DataCach
this.gas_amount = gas;
this.exec_fee_factor = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultExecFeeFactor : NativeContract.Policy.GetExecFeeFactor(Snapshot);
this.StoragePrice = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultStoragePrice : NativeContract.Policy.GetStoragePrice(Snapshot);

if (persistingBlock != null) // Make sure to update the nonce when a new Block is persisting
{
nextNonce = persistingBlock.Nonce;
}
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/neo/SmartContract/Native/TrimmedBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ StackItem IInteroperable.ToStackItem(ReferenceCounter referenceCounter)
Header.PrevHash.ToArray(),
Header.MerkleRoot.ToArray(),
Header.Timestamp,
Header.Nonce,
Header.Index,
Header.PrimaryIndex,
Header.NextConsensus.ToArray(),
Expand Down
31 changes: 31 additions & 0 deletions tests/neo.UnitTests/Cryptography/UT_Murmur128.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography;
using System.Text;
namespace Neo.UnitTests.Cryptography
{
[TestClass]
public class UT_Murmur128
{

[TestMethod]
public void TestGetHashSize()
{
Murmur128 murmur128 = new Murmur128(1);
murmur128.HashSize.Should().Be(128);
}

[TestMethod]
public void TestHashCore()
{
byte[] array = Encoding.ASCII.GetBytes("hello");
array.Murmur128(123u).ToHexString().ToString().Should().Be("0bc59d0ad25fde2982ed65af61227a0e");

array = Encoding.ASCII.GetBytes("world");
array.Murmur128(123u).ToHexString().ToString().Should().Be("3d3810fed480472bd214a14023bb407f");

array = Encoding.ASCII.GetBytes("hello world");
array.Murmur128(123u).ToHexString().ToString().Should().Be("e0a0632d4f51302c55e3b3e48d28795d");
}
}
}
1 change: 0 additions & 1 deletion tests/neo.UnitTests/Cryptography/UT_Murmur3.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography;

namespace Neo.UnitTests.Cryptography
{
[TestClass]
Expand Down
2 changes: 1 addition & 1 deletion tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void TestGetSize()
{
TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction();
tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash };
tblock.Size.Should().Be(138);
tblock.Size.Should().Be(146); // 138 + 8
}

[TestMethod]
Expand Down
Loading