Skip to content

Instantly share code, notes, and snippets.

@ekaitz-zarraga
Last active January 2, 2018 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ekaitz-zarraga/02d58874b0d9757187594319b1ed84bd to your computer and use it in GitHub Desktop.
Save ekaitz-zarraga/02d58874b0d9757187594319b1ed84bd to your computer and use it in GitHub Desktop.
Pseudocode for CryptoNight made in CoffeeScript
# Pseudocode for Cryptonight
# --------------------------
#
# Written in CoffeeScript for simplicity but untested.
# See:
# https://cryptonote.org/cns/cns008.txt
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
get_keccak_state = (input)->
keccak_block_width = 1600 # b
keccak_capacity = 512 # c
# final_state expects a list of bytes for simplicity
final_state = keccak input, keccak_block_width, keccak_capacity
return final_state
scratchpad_init = (final_state)->
scratchpad = []
# +-------------------------------------------------------------+
# | Final state |
# +-------------+--------------+---------------+----------------+
# | Bytes 0..31 | Bytes 32..63 | Bytes 64..191 | Bytes 192..199 |
# +-------------+--------------+---------------+----------------+
# Make the keys with the first part of the final state
# Expand to 10 round keys
keys = aes256_expand_key final_state[0..31], 10
# Make 8 blocks of 16 bytes with the third part of the final state
initial_blocks = final_state[64..191]
blocks = []
for i in [0..7]
blocks[i] = initial_blocks[i*16..(i+1)*(16)]
# Fill the scratchpad
s_byte = 0
while s_byte < 2097152
# Encrypt each block where aes256_round function does: SubBytes,
# ShiftRows and MixColumns on the block and the result is XORed with
# the key. Note: the first and the last are not special like in
# standard AES.
for i in [0..9]
blocks = (aes256_round b, keys[i] for b in blocks)
for block in blocks
for byte in block
scratchpad[s_byte] = byte
s_byte++
return scratchpad
memory_hard_loop = (final_state, scratchpad) ->
# define a and b variables
vars = xor final_state[0..31], final_state[32..63]
a = vars[0..15]
b = vars[16..31]
# Memory-hard loop
iter = 0
while iter < 524288
addr = to_scratchpad_address a
scratchpad[addr] = aes256_round scratchspad[addr], a
[b, scratchpad[addr]] = [scratchpadd[addr], xor b, scratchpad[addr]]
addr = to_scratchpad_address b
a = _8byte_add( a, _8byte_mul(b, scratchpad[addr]))
[a, scratchpad[addr]] = [xor(a, scratchpad[addr]), a]
iter++
# Result calculation
keys = aes256_expand_key final_state[32..63], 10
block = final_state[64..191]
iters = 0
while iters < scratchpad.length()/128
# Encrypt like before
block = xor block, scratchpad[i..i*128-1]
for i in [0..9]
block = aes256_round block, keys[i]
iters++
# the bytes 64..191 of the Keccak state are replaced with the result
final_state[64..191] = block
keccak_block_width = 1600 # b
keccak_capacity = 512 # c
modified_state = keccak_f final_modified_state, keccak_block_width, keccak_capacity
# two last bits of the first byte of the modified_state
selector = modified_state[0] % 4
functions =
0: blake_256
1: groestil_256
2: jh_256
3: skein_256
# result:
return functions[selector] modified_state
cryptonight = (input)->
final_state = get_keccak_state input
scratchpad = scratchpad_init final_state
result = memory_hard_loop final_state, scratchpad
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment