For example, we have 126/128 nonces, revealed in cycle 99. /chains/main/blocks/409599/context/raw/json/cycle/98/nonces?depth=1

If I understand correctly, using these nonces we can calculate the random seed. Can anybody explain how to do this?


We will need these operations:

  • blake2b: size 32
  • concat: concatenation of byte arrays

Also, let zero_bytes be 32 zero bytes.

My answer is based on seed_storage.ml and seed_repr.ml, with some experimentation.

Initial seeds

Let's start at the beginning.

The initial preserved_cycles+2 = 7 seeds were determined ahead of time, as follows. The first seed is the hash of the empty message:

seed[0] = blake2b([]) = 0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8

The remaining 6 initial seeds are each computed from the previous:

seed[n] = blake2b(concat(seed[n-1], zero_bytes))

This gives the following initial seeds:

| cycle | seed                                                             |
|     0 | 0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8 |
|     1 | c8db55740733852aa18aa82e108e4475b1abcf3f1f077ac966e9cecca86612ec |
|     2 | 270da140de63850f631d09a95eab26dc39cc92f8feae73875c7cf9aaa3bf4cac |
|     3 | 97d50852c159ada8e9f107e98f693b059ba28336c723e6cd0f6353eb3c0cb415 |
|     4 | 0c7ea5ee0b25b7105f934c6511756ec20abcf5c6eea4d45721c138c3e751469b |
|     5 | beb4d79b65faa3e902e73d031ad6466299f01aab517d303151a99605a259a11e |
|     6 | 5e695ae038c2bdc54706547fc743eb3564ca5a0b4b5d8e9de2ca4780157ca61e |

The next cycle's seed

From here, we use the revealed nonces to compute the next seed from the previous seed:

seed[n] = seed[n-1]
# start with a 'zero nonce':
seed[n] = blake2b(concat(seed[n], zero_bytes))
# then use the revealed nonces:
for nonce in nonces_for[n]:
  seed[n] = blake2b(concat(seed[n], nonce))

The nonces are taken in decreasing level order.

For example, to calculate the random seed for cycle 7, we can grab the nonces revealed over the course of cycle 0:

# The best level seems to be ((n-5)*4096)-1?
# Warning, this is not complete, see below.
# 8191 = ((7-5)*4096)-1
# 0 = 7-7
curl -s http://localhost:18732/chains/main/blocks/8191/context/raw/json/cycle/0/nonces?depth=1 \
   | jq -r '.[] | "\(.[0])\t\(.[1])"' | sort -rnk1 | cut -f2

The first nonce (in decreasing level order) is "1ee95fe66b...", and the last is "d1012e79ab...", so we compute:

# seed == "5e695ae038c2bdc54706547fc743eb3564ca5a0b4b5d8e9de2ca4780157ca61e"

# zero nonce
seed = blake2b(concat(seed, "0000000000000000000000000000000000000000000000000000000000000000"))
# seed == "9b7328e5393a466fc47ef16eb74121939b06e6ec4c17295eb25611f1b76d6a33"

# first nonce
seed = blake2b(concat(seed, "1ee95fe66bb3dc2a62195dd41a07a30835e63b91db395aa64150da3decc3be1c"))
# seed == "f9b94526a502a1d8e4042eba2deb682dd752627ea6e4472187ad1c1e465be0f4")

# ... the other nonces ...
# seed == "469a48304fc415870289ac8bd875b04107381a2471a878a2a8da16e43dfc5880"

# last nonce
seed = blake2b(concat(seed, "d1012e79abc75ffc4228f69ace060e1003c8fff0aa9d58a2d78816713b72c278"))
# seed == "1bcd1d832aff2d72a8d16a9f9e5f994e177e29eac789138b019f0c4a30c4e5ec"

So far so good:

$ curl http://localhost:18732/chains/main/blocks/24575/context/raw/json/cycle/7/random_seed

How to get the nonces?

However, if you keep going, you will run into a problem.

I don't believe it is possible to use context/raw/json/cycle/<cycle>/nonces to get all the revealed nonces. If a nonce is revealed just at cycle dawn, I believe it will be deleted by the protocol immediately upon use, before it is made available via the raw context RPC.

The first problem seems to be the revelation in the block at level 200704.

Of course, if you are building an alt-shell, you will naturally acquire the nonces, and if, like me, you are just curious, this doesn't matter.

  • 1
    Neat explanation, thanks! You made a typo here seed[n] = blake2b(concat(seed[n-1], nonce)) - it should be concat(seed[n], nonce) ;) Btw, I created a gist on C# with generation of a random seed, maybe someone would find it useful. gist.github.com/Groxan/c0f11a896bcf9a43e0fff9ba2e46223b
    – Groxan
    May 16 '19 at 14:44
  • 1
    As for the revelation in the block at level 200704 - it was a surprise for me =) I tried to get the seed an it was incorrect until I appended the last nonce. Sadly, there are so many pitfalls that are not described in the docs.
    – Groxan
    May 16 '19 at 15:03
  • 1
    Whoops, thanks, that is what I get for trying to write imperative pseudocode. ;)
    – Tom
    May 16 '19 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.