|
@@ -7,7 +7,7 @@
|
|
Comments-URI: https://discord.gg/sJqcgtD (channel #pip-0009)
|
|
Comments-URI: https://discord.gg/sJqcgtD (channel #pip-0009)
|
|
Status: Proposed
|
|
Status: Proposed
|
|
Created: 2017-12-17
|
|
Created: 2017-12-17
|
|
- Updated: 2017-12-29 (rev2), 2018-01-01 (typos)
|
|
|
|
|
|
+ Updated: 2017-12-29 (rev2), 2018-01-01 (typos), 2018-02-06 (rev3)
|
|
</pre>
|
|
</pre>
|
|
|
|
|
|
## Summary
|
|
## Summary
|
|
@@ -37,14 +37,13 @@ A low-memory, GPU and ASIC-resistant hash algorithm called **Random Hash** is pr
|
|
|
|
|
|
1. Hashing a nonce requires ```N``` iterations (called rounds)
|
|
1. Hashing a nonce requires ```N``` iterations (called rounds)
|
|
2. Each round selects a random hash function from a set of 16 well-known hash algorithms
|
|
2. Each round selects a random hash function from a set of 16 well-known hash algorithms
|
|
-3. The input at round ```x``` depends on the output from round ```x-1```
|
|
|
|
-4. The input at round ```x``` depends on the output from another previous round ```1..x-1```, randomly selected
|
|
|
|
-5. The input at round x depends on the output from round ```x-1``` **of a different nonce**
|
|
|
|
-6. The input at round ```x``` is a compression of (3), (4) and (5) to ```100 bytes```
|
|
|
|
-7. The output of every round is expanded for memory-hardness
|
|
|
|
-8. Randomness is generated using ```Mersenne Twister``` algorithm
|
|
|
|
-9. Randomness is seeded via ```MurMur3``` checksum of previous round
|
|
|
|
-10. The final round is then hashed again via ```SHA2_256```, in keeping with traditional cryptocurrency approaches.
|
|
|
|
|
|
+3. The input at round ```x``` depends on round ```x-1```
|
|
|
|
+4. The input at round x depends on round ```x-1``` **of a different nonce** determined based on the output from round ```x-1``` for the current nonce
|
|
|
|
+5. The input at round ```x``` is a compression of the outputs of every contributing stage to ```100 bytes```
|
|
|
|
+6. The output of every round is expanded for memory-hardness
|
|
|
|
+7. Randomness is generated using ```Mersenne Twister``` algorithm
|
|
|
|
+8. Randomness is seeded via ```MurMur3``` checksum of previous round
|
|
|
|
+9. The final round is then hashed again via ```SHA2_256```, in keeping with traditional cryptocurrency approaches.
|
|
|
|
|
|
### RandomHash Design
|
|
### RandomHash Design
|
|
|
|
|
|
@@ -75,34 +74,41 @@ A low-memory, GPU and ASIC-resistant hash algorithm called **Random Hash** is pr
|
|
M = 10KB // The memory expansion unit (in bytes)
|
|
M = 10KB // The memory expansion unit (in bytes)
|
|
|
|
|
|
Function RandomHash(blockHeader : ByteArray)
|
|
Function RandomHash(blockHeader : ByteArray)
|
|
- begin
|
|
|
|
- Result := SHA2_256( RandomHash( blockHeader, N) )
|
|
|
|
|
|
+ begin
|
|
|
|
+ let AllOutputs = RandomHash( blockHeader, N)
|
|
|
|
+ seed = Checksum(neighborOutputs[Length(AllOutputs) - 1])
|
|
|
|
+ Result := SHA2_256( Compress(AllOutputs, RandomNumberGenerator(seed)) )
|
|
end
|
|
end
|
|
|
|
|
|
- Function RandomHash(blockHeader : ByteArray, Round : Integer) : ByteArray
|
|
|
|
|
|
+ Function RandomHash(blockHeader : ByteArray, Round : Integer) : list of ByteArray
|
|
begin
|
|
begin
|
|
- let RoundOutputs = array [1..Round] of ByteArray;
|
|
|
|
- let seed = Checksum(blockHeader) // can hash blockHeader first, but not required
|
|
|
|
- let gen = RandomNumberGenerator(seed)
|
|
|
|
- let input = blockHeader
|
|
|
|
|
|
+ let RoundOutputs = list of ByteArray;
|
|
|
|
|
|
- for i = 1 to Round do
|
|
|
|
- let random = gen.NextDWord
|
|
|
|
- let hashFunc = HASH_ALGO[random % 16]
|
|
|
|
- if i = 1 then
|
|
|
|
- let input = blockHeader
|
|
|
|
- else
|
|
|
|
- let prevRound = RoundOutputs[i - 1]
|
|
|
|
- let randPrevRound = RoundOutputs[ random % (i - 1) + 1 ]
|
|
|
|
- let otherNonceHeader = ChangeNonce(blockHeader, random)
|
|
|
|
- let otherNonceRound = RandomHash(otherNonceBlockHeader, i - 1)
|
|
|
|
- let input = Compress(prevRound, randPrevRound, otherNonceRound, gen)
|
|
|
|
- let output = hashFunc(input)
|
|
|
|
- output = Expand( output, N - i, gen )
|
|
|
|
- gen.Seed = Checksum(output)
|
|
|
|
- RoundOutputs[i] = output
|
|
|
|
-
|
|
|
|
- Result = RoundOutputs[Round]
|
|
|
|
|
|
+ if Round = 1 then
|
|
|
|
+ let seed = Checksum(blockHeader) // can hash blockHeader first, but not required
|
|
|
|
+ let gen = RandomNumberGenerator(seed)
|
|
|
|
+ let input = blockHeader
|
|
|
|
+ else
|
|
|
|
+ let parentOutputs = RandomHash(blockHeader, Round - 1)
|
|
|
|
+ RoundOutputs.addAll(parentOutputs)
|
|
|
|
+ let seed = Checksum(neighborOutputs[Length(neighborOutputs) - 1])
|
|
|
|
+ let gen = RandomNumberGenerator(seed)
|
|
|
|
+
|
|
|
|
+ let otherNonceHeader = ChangeNonce(blockHeader, gen.NextDWord)
|
|
|
|
+ let neighborOutputs = RandomHash(blockHeader, Round - 1)
|
|
|
|
+ RoundOutputs.addAll(neighborOutput)
|
|
|
|
+
|
|
|
|
+ // re-seed RNG based on random other nonce output
|
|
|
|
+ seed = Checksum(neighborOutputs[Length(neighborOutputs) - 1])
|
|
|
|
+ gen = RandomNumberGenerator(seed)
|
|
|
|
+ let input = Compress(RoundOutputs, gen)
|
|
|
|
+
|
|
|
|
+ let hashFunc = HASH_ALGO[gen.NextDWord % 16]
|
|
|
|
+ let output = hashFunc(input)
|
|
|
|
+ output = Expand( output, N - i, gen )
|
|
|
|
+ RoundOutputs.add(output)
|
|
|
|
+
|
|
|
|
+ Result := RoundOutputs
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
@@ -128,19 +134,15 @@ A low-memory, GPU and ASIC-resistant hash algorithm called **Random Hash** is pr
|
|
Result = output
|
|
Result = output
|
|
end
|
|
end
|
|
|
|
|
|
- function Compress(input1, input2, input3 : ByteArray, gen : RandomNumberGenerator) : ByteArray
|
|
|
|
|
|
+ function Compress(inputs : list of ByteArray, gen : RandomNumberGenerator) : ByteArray
|
|
begin
|
|
begin
|
|
let output = Byte[0..99]
|
|
let output = Byte[0..99]
|
|
|
|
|
|
for i = 0 to 99 do
|
|
for i = 0 to 99 do
|
|
- var random = gen.NextDWord
|
|
|
|
- case random % 3 do
|
|
|
|
- 0: let source = input1
|
|
|
|
- 1: let source = input2
|
|
|
|
- 2: let source = input3
|
|
|
|
- output[i] = source[random % Length(source)]
|
|
|
|
|
|
+ let source = inputs[ gen.NextDWord % Length(inputs) ]
|
|
|
|
+ output[i] = source[ gen.NextDWord % Length(source) ]
|
|
|
|
|
|
- Result = output
|
|
|
|
|
|
+ Result := output
|
|
end
|
|
end
|
|
|
|
|
|
function ChangeNonce(blockHeader : ByteArray, nonce : Integer) : ByteArray
|
|
function ChangeNonce(blockHeader : ByteArray, nonce : Integer) : ByteArray
|
|
@@ -338,6 +340,9 @@ This PIP is not backwards compatible and requires a hard-fork activation. Previo
|
|
|
|
|
|
A reference implementation will be provided in the coming weeks.
|
|
A reference implementation will be provided in the coming weeks.
|
|
|
|
|
|
|
|
+## Acknowledgements
|
|
|
|
+Refinements to improve GPU-hardness were provided by Ian Muldoon.
|
|
|
|
+
|
|
## Links
|
|
## Links
|
|
|
|
|
|
1. [Mersennne Twister Implementation (Lazarus/FPC)][1]
|
|
1. [Mersennne Twister Implementation (Lazarus/FPC)][1]
|