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?
Tezos Stack Exchange is a question and answer site for users, experts, and developers of the Tezos blockchain project. It only takes a minute to sign up.
Sign up to join this communityFor 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 32concat
: concatenation of byte arraysAlso, let zero_bytes
be 32 zero bytes.
My answer is based on seed_storage.ml and seed_repr.ml, with some experimentation.
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 |
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
"1bcd1d832aff2d72a8d16a9f9e5f994e177e29eac789138b019f0c4a30c4e5ec"
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.
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