Not that we (friends and I) put that much effort into this but the “how” can be
useful to others: basically some quick and dirty use of the tezos-crypto
OCaml
library. We didn't get even close to the right solution, but this was also a
good occasion to do some experiments with code annotated in SVG (!).
Checkout the challenge in the blog
post
by @chainofinsight : The Oracle of
Delphi, a Tezos Puzzle. And, what most people got drawn to: the list of
oracular statements from Delphi around 480 BC on
Wikipedia .
Friends found the phrase “Pray to the Winds. They will prove to be mighty
allies of Greece.” and had tried SmartPy's
sp.test_account
and
Flextesa's deterministic key-pairs:
docker run --rm tqtezos/flextesa:20200925 flextesa key-of-name "Pray to the Winds"
We thought we needed to find 32 bytes to create an
Ed25519 private key — because of
the 1
in tz1……
— cf. the
implementation .
Myself had too much zoom-fatigue and too many preemptive slackterruptions to be
able to read through “Greek mythology wikipedia” or to stare at an image, so did
not notice any Bip39 word. But I was OK with spending a little time here and
there hammering at the problem with some OCaml.
So
here
it is.
I use dune utop src/lib_crypto/
in the Tezos repository to start utop
and
then use #use
to load and run the script because I happen to always have
those things available. But it should just work with
opam install tezos-crypto
; let me know if it doesn't.
The SVG experiment went like this:
highlight delphi-oracle.ml --src-lang=ocaml --inline-css -O html -o delphi-oracle.html
Then the HTML output was cleaned-up with libreoffice
and exported to a PDF
which was then imported into an Inkscape project. The build system of the blog
then keeps calling inkscape
with --export-plain-svg
and we get:
image/svg+xml
;;
#require
"fmt"
;;
#require
"base"
open
Base
let
make
metaseed =
let
of_seed
seed =
try
let
pkh
, pk, sk =
Tezos_crypto
.
Ed25519
.generate_key ~seed:(
Bytes
.of_string seed) ()
in
Some
( seed,
Tezos_crypto
.
Ed25519
.
Public_key_hash
.to_b58check
pkh
,
Tezos_crypto
.
Ed25519
.
Secret_key
.to_b58check sk )
with
_ -> None
in
let
all
=
let
clean
=
String
.filter ~f:(
function
‘
.’ | ‘ ‘ ->
false
| _ ->
true
)
in
let
odd
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
1
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
even
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
0
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
blake2b
s =
Tezos_crypto
.
Blake2B
.hash_string [ s ] |>
Tezos_crypto
.
Blake2B
.to_string
in
let
sha256
s =
Tezos_crypto
.
Hacl
.
Hash
.
SHA256
.digest (
Bytes
.of_string s)
|>
Bytes
.to_string
in
let
mirror
s = s ^
String
.rev s
in
List
.filter_map ~f:
of_seed
[
metaseed;
String
.lowercase metaseed;
String
.uppercase metaseed;
clean
metaseed;
String
.lowercase (
clean
metaseed);
String
.uppercase (
clean
metaseed);
odd
metaseed;
odd
(
String
.lowercase metaseed);
even
metaseed;
even
(
String
.lowercase metaseed);
blake2b
metaseed;
blake2b
(
String
.lowercase metaseed);
blake2b
(
String
.uppercase metaseed);
sha256
metaseed;
sha256
(
String
.lowercase metaseed);
sha256
(
String
.uppercase metaseed);
String
.rev metaseed;
String
.rev (
String
.lowercase metaseed);
String
.rev (
String
.uppercase metaseed);
mirror
metaseed;
mirror
(
String
.lowercase metaseed);
mirror
(
String
.uppercase metaseed);
]
in
let
truth
=
"tz1V7rDn1uhSnGPnfj3ebuHS5nqjYEBU3QGF"
in
Fmt
.pr
"Metaseed:
%S
\n
"
metaseed;
List
.iter
all
~f:(
fun
(seed,
pkh
, sk) ->
Fmt
.pr
"
%s %s
(
%S
,
%d
)
%s
\n
%!"
pkh
sk seed (
String
.length seed)
(
if
String
.equal
truth pkh
then
failwith seed
else
""
))
let
() =
make
"Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds.
\n
They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds."
;
make
": Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"They will prove to be mighty allies of Greece."
;
()
;;
#require
"fmt"
;;
#require
"base"
open
Base
let
make
metaseed =
let
of_seed
seed =
try
let
pkh
, pk, sk =
Tezos_crypto
.
Ed25519
.generate_key ~seed:(
Bytes
.of_string seed) ()
in
Some
( seed,
Tezos_crypto
.
Ed25519
.
Public_key_hash
.to_b58check
pkh
,
Tezos_crypto
.
Ed25519
.
Secret_key
.to_b58check sk )
with
_ -> None
in
let
all
=
let
clean
=
String
.filter ~f:(
function
'.' | ' ' ->
false
| _ ->
true
)
in
let
odd
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
1
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
even
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
0
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
blake2b
s =
Tezos_crypto
.
Blake2B
.hash_string [ s ] |>
Tezos_crypto
.
Blake2B
.to_string
in
let
sha256
s =
Tezos_crypto
.
Hacl
.
Hash
.
SHA256
.digest (
Bytes
.of_string s)
|>
Bytes
.to_string
in
let
mirror
s = s ^
String
.rev s
in
List
.filter_map ~f:
of_seed
[
metaseed;
String
.lowercase metaseed;
String
.uppercase metaseed;
clean
metaseed;
String
.lowercase (
clean
metaseed);
String
.uppercase (
clean
metaseed);
odd
metaseed;
odd
(
String
.lowercase metaseed);
even
metaseed;
even
(
String
.lowercase metaseed);
blake2b
metaseed;
blake2b
(
String
.lowercase metaseed);
blake2b
(
String
.uppercase metaseed);
sha256
metaseed;
sha256
(
String
.lowercase metaseed);
sha256
(
String
.uppercase metaseed);
String
.rev metaseed;
String
.rev (
String
.lowercase metaseed);
String
.rev (
String
.uppercase metaseed);
mirror
metaseed;
mirror
(
String
.lowercase metaseed);
mirror
(
String
.uppercase metaseed);
]
in
let
truth
=
"tz1V7rDn1uhSnGPnfj3ebuHS5nqjYEBU3QGF"
in
Fmt
.pr
"Metaseed:
%S
\n
"
metaseed;
List
.iter
all
~f:(
fun
(seed,
pkh
, sk) ->
Fmt
.pr
"
%s %s
(
%S
,
%d
)
%s
\n
%!"
pkh
sk seed (
String
.length seed)
(
if
String
.equal
truth pkh
then
failwith seed
else
""
))
let
() =
make
"Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds.
\n
They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds."
;
make
": Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"They will prove to be mighty allies of Greece."
;
()
;;
#require
"fmt"
;;
#require
"base"
open
Base
let
make
metaseed =
let
of_seed
seed =
try
let
pkh
, pk, sk =
Tezos_crypto
.
Ed25519
.generate_key ~seed:(
Bytes
.of_string seed) ()
in
Some
( seed,
Tezos_crypto
.
Ed25519
.
Public_key_hash
.to_b58check
pkh
,
Tezos_crypto
.
Ed25519
.
Secret_key
.to_b58check sk )
with
_ -> None
in
let
all
=
let
clean
=
String
.filter ~f:(
function
‘
.’ | ‘ ‘ ->
false
| _ ->
true
)
in
let
odd
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
1
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
even
s =
let
x
=
ref
0
in
String
.filter
~f:(
function
| _
when
!
x
%
2
=
0
->
Caml
.incr
x
;
true
| _ ->
Caml
.incr
x
;
false
)
s
in
let
blake2b
s =
Tezos_crypto
.
Blake2B
.hash_string [ s ] |>
Tezos_crypto
.
Blake2B
.to_string
in
let
sha256
s =
Tezos_crypto
.
Hacl
.
Hash
.
SHA256
.digest (
Bytes
.of_string s)
|>
Bytes
.to_string
in
let
mirror
s = s ^
String
.rev s
in
List
.filter_map ~f:
of_seed
[
metaseed;
String
.lowercase metaseed;
String
.uppercase metaseed;
clean
metaseed;
String
.lowercase (
clean
metaseed);
String
.uppercase (
clean
metaseed);
odd
metaseed;
odd
(
String
.lowercase metaseed);
even
metaseed;
even
(
String
.lowercase metaseed);
blake2b
metaseed;
blake2b
(
String
.lowercase metaseed);
blake2b
(
String
.uppercase metaseed);
sha256
metaseed;
sha256
(
String
.lowercase metaseed);
sha256
(
String
.uppercase metaseed);
String
.rev metaseed;
String
.rev (
String
.lowercase metaseed);
String
.rev (
String
.uppercase metaseed);
mirror
metaseed;
mirror
(
String
.lowercase metaseed);
mirror
(
String
.uppercase metaseed);
]
in
let
truth
=
"tz1V7rDn1uhSnGPnfj3ebuHS5nqjYEBU3QGF"
in
Fmt
.pr
"Metaseed:
%S
\n
"
metaseed;
List
.iter
all
~f:(
fun
(seed,
pkh
, sk) ->
Fmt
.pr
"
%s %s
(
%S
,
%d
)
%s
\n
%!"
pkh
sk seed (
String
.length seed)
(
if
String
.equal
truth pkh
then
failwith seed
else
""
))
let
() =
make
"Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds.
\n
They will prove to be mighty allies of Greece."
;
make
"Pray to the Winds."
;
make
": Pray to the Winds. They will prove to be mighty allies of Greece."
;
make
"They will prove to be mighty allies of Greece."
;
()
My standard imports, on top of tezos-crypto.
The metaseed is the input “phrase” — See the `let ()` at the end.
We care about a public-key-hash (tz1..) and a secret-key compatible with tezos-client; both using a base58check encoding.
We are looking for a tz1 address, hence Ed25519.
Create a key-pair in the most obvious way for a given seed string. It only uses the first 32 bytes, but fails with less of them.
We build the list of “all” seed candidates from the metaseed. Then follows a list of functions making seeds out of strings …
Dumbest quick-and-dirty “take the odd/even characters” implementations.
Hash functions like Blake2B or SHA256 seemed nice because they bring the size of the seed to a constant; moreover that sounded like something some wallet software could have done to get a key from a passphrase …
Shoot out to formally verified crypto-primitives!
A list of seeds & the function string → account option.
The address we were looking for.
We interrupt the search on success.
A few of the phrases that we tried, in vain :)
Those to_string functions are not for human-readable; it's just the OCaml string type, as a byte-array.