Example of memorizing a 256-bit private key

There are techniques that can enable anyone to memorize much more than may seem possible. This post will show how I generated and memorized a 256-bit encryption key this morning using the approach explained here.


There ain’t no such thing as a free lunch. This saying is abbreviated TANSTAAFL in Heinlein’s novel The Moon is a Harsh Mistress. It takes effort to safe effort.

Memorization techniques make it easier to remember new things if you invest effort into the techniques. The more you invest into the techniques, the easier memorizing new things is.

Whether this investment is practical depends on the person. I find it more interesting than practical; I rarely need to memorize anything. But I know of people who have used these techniques to great advantage.

Generating a key

First, I’ll generate a 256-bit number using Python.

>>> import secrets
>>> s = secrets.randombits(256)

This produced the following:


If you were to run the same code you would not get the same number, which is the point of the secrets module. It seeds a random number generator with entropy extracted from the state of the computer it is running on.

Parsing digits

The number above has 77 digits, so I split it into a two-digit number, 14, and 25 three-digit numbers: 769, 232, …, 581. Then using Major mnemonic system encoding, I associate each number with a letter of the NATO phonetic alphabet.

I encode 14 as “tar”, and the NATO word for the letter A is “alpha,” so I imagine an alpha male covered in tar.

I encode 769 as “ketchup,” and the NATO word for B is “bravo,” so I imagine a brave bottle of ketchup, arms akimbo, and wearing a superhero cape.

I encode 581 as “elevator” [1], and the phonetic word for Z is Zulu, and so I imagine Shaka Zulu riding in an elevator.

Using this process I memorized the random number above in a few minutes.

Just for fun I asked DALL-E 2 to produce an image of “Shaka Zulu, spear in hand, riding in an elevator” the image below is one of the ones it created.

Shaka Zulu, spear in hand, riding in an elevator

Related posts

[1] Strictly speaking, “elevator” decodes as 5814. But I use a common convention of only considering the first three consonants in a word. This is a good trade-off because it’s not likely you could encode a 4-digit number in a single word.

How to memorize the periodic table

Periodic table image


Memorizing the periodic table has some practical value, especially if you’re a chemist, but in any case it’s an interesting exercise, easier to do than it may sound. And it’s a case study for how you might memorize other things of more practical value to you personally.

Major system pegs

The Major system is a way to associate consonant sounds to numbers. You can fill in vowels and semivowels as you please to turn the sequence of consonant sounds into words, preferably words that create a vivid image in your mind.

You can pick a canonical encoding of each number to create a set of pegs and use these to memorize numbered lists. Although numbers can be encoded many ways, a set of pegs is a one-to-one mapping to numbers. To pull up the nth item in the list, recall what image you’ve associated with the peg image for n.

For example, you could encode 16 as dish, tissue, touché, Hitachi, etc. If you want to remember that sulfur has atomic number 16 you could use any of those images. But if you wanted to remember that the 16th element is sulfur, you need to have a unique peg associated with 16.

Learning pegs is more work than hanging things on pegs. But once you have a set of pegs, you can reuse them for memorizing multiple lists. For example, you could use the same pegs to memorize the periodic table and the ASCII table.

Atomic numbers

Allan Krill has written up a way to associate each element with a peg. You could use his suggestions, but you’ll almost certainly need to customize some of them. It’s generally hard to use anyone else’s mnemonics. What works for one person may not for another.

To memorize the periodic table, you first come up with pegs for the numbers 1 through 118. Practice those and get comfortable with them. This could take a while, but it’s reusable effort. Then associate an image of each element with its corresponding peg. For example, polonium is element 84. If your peg for 84 is fire, you might imagine someone playing polo on a field that’s on fire.

Element symbols

Every element has a one- or two-letter symbol, and most of these are easy: Ti for titanium, U for uranium, etc. Some seem completely arbitrary, such as Hg for mercury, but these you may already know. These names seem strange because they are mnemonic in Latin. But the elements with Latin names are also the ones that were discovered first and are the most common. You probably know by osmosis, for example, that the symbol for iron is Fe.

The hard part is the second letter, if there is a second letter. For example, is does Ar stand for argon or arsenic? Is the symbol for thulium Th or Tl or Tm?

When you associate an element image with a peg image, you could add a third image for the second letter of the element symbol, using the NATO phonetic alphabet if you know that. For example, the NATO word for S is Sierra. If your peg for 33 is mummy, you might imagine a mummy drinking a bottle of Sierra Springs® water laced with arsenic.

Related posts

Image from OpenStax Biology 2e. CC BY Attribution license.

How to memorize a Bitcoin address

The latest episode of Darknet Diaries interviews someone using the pseudonym Default. He says in the interview that he had nearly a thousand Bitcoins (about $36 M) in a wallet stored on an external hard drive that was seized by federal agents when they raided his home. Default went to prison for five years for some audacious hacking, but now he’s out and the feds won’t give him his hard drive back.

Default isn’t the only person who has lost a fortune because he lost a number. It’s fairly common.

If Default had memorized his account number(s) he’d be rich today. Memorizing a Bitcoin address or a private key would take some work, but I’d do it for a million dollars. I’d do it for a whole lot less than that because it’s not that much work.

I’ll present two ways to memorize addresses and keys. I’ll start with addresses.

How long is a Bitcoin address?

A Bitcoin address is essentially [1] a 200-bit number encoded in base 58. Why base 58? That’s 10 digits, 26 lower case letters, and 26 upper case letters, with four visually similar characters removed. The characters 1, l, and I are similar, as are 0, o, and O. Base 58 keeps the numeral 1 and the lower case letter o and discards the characters that look similar to these. More on base 58 encoding here.

So you can think of a Bitcoin address as either a 200-bit number or a string of 34 alphanumeric characters.

Base 58

The most direct approach would be to memorize the address in its base 58 form. This is a string of 34 alphanumeric characters. As I mention here, I memorize numbers using the Major system, and letters using the NATO alphabet. To distinguish lower case and upper case I have two variants of each NATO name, a large object for capital letters and a small object for lower case letters. For example, golf cart for G and golf ball for g.


A 200-bit number corresponds to a 60-digit number. It’s easier to memorize 60 digits than to memorize 34 alphanumeric characters because the digits can easily be chunked into groups whereas the alphanumeric characters cannot.

You can go back and forth between base 58 encoding of an address and hexadecimal using this online calculator and you can go between hexadecimal and decimal easily in any programming language.

For example, I typed the address


into the online calculator and got back


Then I appended 0x to this and typed it into the Python REPL to get a decimal number.

    >>> 0x00F54A5851E9372B87810A8E60CDD2E7CFD80B6E31C7F18FE8

There are two ways to group digits for memorization: regularly and irregularly.

Irregular grouping

The Major system for memorizing numbers is typically presented using irregular grouping. You convert each digit into a consonant sound and improvise a way a grouping the consonants into words. Some words may encode one or two digits, some three digits. You might get lucky occasionally and be able to group four digits into a single word. Then you create mental images that string the words together.

In the example above, you might divide the number into 60 1450 33 … which you could encode as “goose drills mummy …” and maybe you’d imaging a goose as a drill sergeant, barking at a mummy soldier, etc.

Regular grouping

It’s easy to get started with irregular grouping, but regular grouping has its advantages. You might group your 60 digits into 30 pairs or 20 triples. If you’re using two-digit groups, you might have a rule that only the first two consonant sounds count, giving yourself the freedom to use words that have more than two consonant sounds. Of course you could have an analogous rule for three digits.

If you break a 60-digit address into 20 three-digit numbers, and convert each three-digit number to a word, you have to memorize a sequence of 20 words. Choose words that are easy to visualize, and you have to remember a sequence of 20 images. That takes some effort, but people go to greater effort to save Bitcoin addresses.

Private keys

Private keys are little longer than addresses, 256 bits rather than 200. The same principles apply. A 256-bit number corresponds to a 77 or 78 digit number. If you divide 78 digits into groups of (average) length 3, that’s 26 words to memorize. Since 26 happens to be the number of letters in the English alphabet, you could associate each word with a letter of the alphabet, say using the NATO alphabet, to make sure you remember the worlds in the correct order.

Related posts

[1] You can find details here. You start with the output of a 160-bit hashing algorithm, and add 40 bits of checksum and version information. The encoding is not strictly base 58 encoding but rather Base 58 Check, which at its core is base 58 encoding.

Photo by Lukas Eggers on Unsplash

Using WordNet to create a PAO system

NLP software infers parts of speech by context. For example, the SpaCy NLP software can determine the parts of speech in the poem Jabberwocky even though the words are nonsense. More on this here.

If you want to tell the parts of speech for isolated words, maybe software like SpaCy isn’t the right tool. You might use lists of nouns, verbs, etc. This is what I’ll do in this post using the WordNet corpus. I’d like to show how you could use WordNet to create a mnemonic system.

PAO (person-action-object)

One way that people memorize six-digit numbers, or memorize longer numbers six digits at a time, is the PAO (person-action-object) system. They memorize a list of 100 people, 100 actions, and 100 direct objects. The first two digits of a six-digit number are encoded as a person, the next two digits as an action, and the last two digits as an object. For example, “Einstein dances with a broom” might encode 201294 if 20 is associated with Einstein, 12 with dance, and 94 with broom.

These mappings could be completely arbitrary, but you could memorize them faster if there were some patterns to the mappings, such as using the Major mnemonic system.

I’ve written before about how to use the CMU Pronouncing Dictionary to create a list of words along with the numbers they correspond to in the Major system. This post will show how to pull out the nouns and verbs from this list. The nouns are potential objects and the verbs are potential actions. I may deal with persons in another post.

Noun and verb lists in WordNet

The WordNet data contains a file index.noun with nouns and other information. We want to discard the first 29 lines of preamble and extract the nouns in the first column of the file. We can do this with the following one-liner.

   tail -n +30 index.noun | cut -d' ' -f1 > nouns.txt

Likewise we can extract a list of verbs with the following

   tail -n +30 index.verb | cut -d' ' -f1 > verbs.txt

There is some overlap between the two lists since some words can be nouns or verbs depending on context. For example, running

   grep '^read$' nouns.txt


   grep '^read$' verbs.txt

shows that “read” is in both lists. (The regex above anchors the beginning of the match with ^ and the end with $ so we don’t get unwanted matches like “treadmill” and “readjust.”)

Sorting CMU dictionary by part of speech

The following Python code will parse the file cmu_major.txt from here to pull out a list of nouns and a list of verbs, along with their Major system encodings.

    with open("nouns.txt") as f:
        nouns = set()
        for line in f.readlines():
    with open("verbs.txt") as f:
        verbs = set()
        for line in f.readlines():
    cmunouns = open("cmu_nouns.txt", "w")
    cmuverbs = open("cmu_verbs.txt", "w")
    with open("cmu_major.txt") as f:
        for line in f.readlines():
            w = line.split()[0].lower()
            if w in nouns:
            if w in verbs:

You can download the output if you’d like: cmu_nouns.txt, cmu_verbs.txt.

Going back to the example of 201294, the file cmu_verbs.txt contains 82 words that correspond to numbers starting with 12. And the file cmu_nouns.txt contains 1,057 words that correspond to numbers starting with 94.

Choosing verbs is the hard part. Although there are verbs for every number 00 through 99, many of these would not be good choices. You want active verbs that can be combined with any subject and object.

My impression is that most people who use the PAO system—I do not—pick their names, verbs, and objects without regard to the Major system, and I could understand why: your choices are sometimes limited if you want to be compatible with the Major system. You might compromise and use Major-compatible pegs when possible and make exceptions as needed.

Memorizing four-digit numbers

The Major mnemonic system is a method of converting numbers to words that can be more easily memorized. The basics of the system can be written on an index card, but there are practical details that are seldom written down.

Presentations of the Major system can be misleading, intentionally or unintentionally, by implying that it is easy to find single words that encode numbers with three or four digits. Books and articles can unintentionally leave a wrong impression by being brief, but I can think of one book that I thought was intentionally misleading, opening with an example that was obviously reverse-engineered from its mnemonic. It was something like “Isn’t it easier to remember ‘constitution’ than 7201162?” Indeed it is, but I make up that example by starting with “constitution,” not starting with 7201162.

The Major system maps digits to consonant sounds. Spelling doesn’t matter, only pronunciation, and you can insert any vowels (or semivowels) you like. I list the mapping here in ARPAbet notation and here in IPA notation. The former is less precise but easier for most people to understand, so I’ll repeat it here.

0: S or Z
1: D, DH, T, or DH
2: N or NG
3: M
4: R
5: L
6: CH, JH, SH, or ZH
7: G or K
8: F or V
9: P or B

It is easy to find words that encode single digits. It’s a little harder to find words that encode some two-digit numbers, but it’s certainly doable. But if you want to encode all three-digit numbers as single words, you have to make some compromises. I estimate there’s about a 52% chance of being able to encode a four-digit number as a single word, for reasons I’ll explain below.

The CMU Pronouncing Dictionary lists 134,373 words along with their ARPAbet pronunciation. In this post I describe how I mapped the words to numbers, creating a file cmu_major.txt.

Not every three-digit number is in this file. The command

    grep -P -o ' \d{3}$' cmu_major.txt | sort -u | wc -l

shows that there are 958 unique three-digit numbers in the file, i.e. 42 three-digit numbers cannot be encoded as words in the CMU dictionary. By changing the ‘3’ to a ‘4’ in the one-liner above we see there are 5,191 unique four-digit numbers in the file, i.e. about 52% of all possible four-digit numbers.

Since it is very often not possible to encode numbers with four or more digits as single words, a common approach is to not try. Instead, just pay attention to the first three digits that a word would encode. The advantage of this is that it opens up more possibilities for encoding three-digit numbers. The downside is that you give up the possibility of encoding four-digit numbers in a single word, but this isn’t giving up much since there’s a 40% chance you’d fail anyway.

So if you want to memorize a four-digit number, you could memorize a pair of two-digit numbers. Some people like to draw these two numbers from different sets, such as using the name of a person for the first two digits and an action for the second two digits. I’ll explore this more in my next post on the PAO system.

Code to convert words to Major system numbers

A few days ago I wrote about using the CMU Pronouncing Dictionary to search for words that decode to certain numbers in the Major mnemonic system. You can find a brief description of the Major system in that post.

As large as the CMU dictionary is, it did not contain words mapping to some three-digit numbers, so it would be good to explore a larger, or at least different, dictionary. But the CMU dictionary is apparently the largest dictionary with pronunciation openly available.

To get more pronunciation data, you’ll need to generate it. This is what linguists call the grapheme to phoneme problem. There are software packages that create phonetic spellings using large neural network models, including models trained on the CMU data.

Why quick-and-dirty is OK

However, it’s possible to do a good enough job with much simpler software. There are several reasons why we don’t need the sophistication of research software. First and foremost, we can tolerate errors. If we get a few false positives, we can skim through those and ignore them. And if we get a few false negatives, that’s OK as long as we find a few of the words we’re looking for.

Another thing in our favor is that we’re not looking for pronunciation per se, only the numbers generated from the pronunciation. The hardest part of the grapheme to phoneme problem is vowel sounds, and we don’t care about vowel sounds at all. And we don’t care about distinguishing, for example, between voiced and unvoiced variations on the th sound because they both map to 1.


The Major mnemonic system is based on pronunciation, not spelling. Nevertheless, you can do a rough-and-ready conversion, adequate for our purposes, based on spelling. I take into account a minimal amount of context, such as noting that c is soft before i, e, and y, but hard before a, o, and u. The handling of ch is probably biggest source of errors because the sound of ch depends on etymology.

I wrote this as a Python script initially because I wanted to share it with someone who knows Python. But I’ll present it here in Perl because the Perl code is much more compact.

sub word2num {
    local $_ = shift;
    tr/A-Z/a-z/; # lower case
    s/g[iey]/j/g; # soft g -> j
    s/c[eiy]/s/g; # soft c -> s
    s/c[aou]/k/g; # hard c -> k
    s/([bflmprv])\1+/\1/g; # condense double letters

    tr/a-z//d; # remove remaining letters
    return $_

Perl has implicit variables, for better and for worse, and here it’s for the better. All the translation (tr//) and substitution (s//) operate in place on the implicit argument, the word sent to the function.

The corresponding Python code is more verbose:

def word2num(w):

    w = w.lower()

    w = w.replace('ng', 'n')
    w = w.replace('sch', 'j')
    w = w.replace('che', 'k')

    for x in ['gi', 'ge', 'gy', 'ch', 'sh']:
        w = w.replace(x, 'j')


The order of the replacement statements matters. For example, you want to decide whether c and g are hard before you discard the vowels.

This script works better than I expected it would for being such a dirty hack. I ran it on some large word lists looking for more alternatives to the three-digit numbers not in the output of the script processing the CMU dictionary. I list a few of the words I found here. The most amusing find was phobophobia, the fear of phobias, for 898.

Aside from filling in gaps in three-digit numbers, you could also use a script like this to search for mnemonic words in specialized lists of words, such as baseball players, or animal species, or brand names.

ARPAbet and the Major mnemonic system


ARPAbet is a phonetic spelling system developed by— you guessed it—ARPA, before it became DARPA.

The ARPAbet system is less expressive than IPA, but much easier for English speakers to understand. Every sound is encoded as one or two English letters. So, for example, the sound denoted ʒ in IPA is ZH in ARPAbet.

In ARPAbet notation, the Major mnemonic system can be summarized as follows:

0: S or Z
1: D, DH, T, or DH
2: N or NG
3: M
4: R
5: L
6: CH, JH, SH, or ZH
7: G or K
8: F or V
9: P or B

Numbers are encoded using the consonant sounds above; the system is based on sounds and not on spelling. You can insert any vowels or semivowels (e.g. w or y) you like. For example, you could encode 648 as “giraffe” or 85 as “waffle.”

The CMU Pronouncing Dictionary lists 134,373 words along with their ARPAbet pronunciation. The Python code below will read in the pronouncing dictionary and produce a Major mnemonic dictionary. The resulting file is available here as a zip compressed text file.

To find a word that encodes a number, search the code output for that number. For example,

    grep ' 648' cmu_major.txt

will find words whose Major encoding begins with 648, and

    grep ' 648$' cmu_major.txt

fill find words whose Major encoding is exactly 648.

From this we learn that “sheriff” is another possible encoding for 648.

Filling in the gaps

Suppose you’re looking for encodings for all three digit numbers, 000 through 999. This can be hard to do. A common compromise is to only regard up to the first three consonants in a word. For example, you might use “ladybug” to encode 519, ignoring the final G sound on the end.

The tradeoff is that if you adopt this rule then you can’t use “ladybug” to encode 5197. But finding single words that encode 4-digit numbers can be challenging if not impossible, so you may just forego the possibility. (I quantify this here.) This is why in the example above I show both searching for numbers that begin with 648 and numbers that are exactly 648.

Despite the large size of the CMU dictionary, it does not contain words that map to numbers beginning with 42 three-digit numbers. I can offer suggestions for these numbers, but it’s hard to use anyone else’s mnemonics. You may have to make up your own, using, for example, names of people you know personally or brand names you’re familiar with etc.

Python code

# NB: File encoding is Latin-1, not UTF-8.
with open("cmudict-0.7b", "r", encoding="latin-1") as f:
    lines = f.readlines()

for line in lines:
    line.replace('0','') # remove stress notation
    pieces = line.split()
    numstr = ""
    for p in pieces[1:]:
        match p:
            case "S" | "Z":
                numstr += "0"
            case "D" | "DH" | "T" | "DH":
                numstr += "1"
            case "N" | "NG":
                numstr += "2"
            case "M":
                numstr += "3"
            case "R":
                numstr += "4"
            case "L":
                numstr += "5"
            case "CH" | "JH" | "SH" | "ZH":
                numstr += "6"
            case "G" | "K":
                numstr += "7"
            case "F" | "V":
                numstr += "8"
            case "P" | "B":
                numstr += "9"
    print(pieces[0], numstr)

How to memorize Unicode codepoints

At the end of each month I write a newsletter highlighting the most popular posts of that month. When I looked back at my traffic stats to write this month’s newsletter I noticed that a post I wrote last year about how to memorize the ASCII table continues to be popular. This post is a follow up, how to memorize Unicode values.

Memorizing all 128 ASCII values is doable. Memorizing all Unicode values would be insurmountable. There are nearly 150,000 Unicode characters at the moment, and the list is grows over time. But knowing a few Unicode characters is handy. I often need to insert a π symbol, for example, and so I made an effort to remember its Unicode value, U+03C0.

There are convenient ways of inserting common non-ASCII characters without knowing their Unicode values, but these offer a limited range of characters and they work differently in different environments. Inserting Unicode values gives you access to more characters in more environments.

As with ASCII, you can memorize the Unicode value of a symbol by associating an image with a number and associating that image with the symbol. The most common way to associate an image with a number is the Major system. As with everything else, the Major system becomes easier with practice.

However, Unicode presents a couple challenges. First, Unicode codepoints are nearly always written in hexadecimal, and so you’ll run into the letters A through F as well as digits. Second, Unicode codepoints are four hex digits long (or five outside the Basic Multilingual Plane.) We’ll address both of these difficulties shortly.

It may not seem worthwhile to go to the effort of encoding and decoding numbers like this, but it scales well. Brute force is fine for small amounts of data and short-term memory, but image association works much better for large amounts of data and long-term memory.

Unicode is organized into blocks of related characters. For example, U+22xx are math symbols and U+26xx are miscellaneous symbols. If you know what block a symbols is in, you only need to remember the last two hex digits.

You can convert a pair of hex digits to decimal by changing bases. For example, you could convert the C0 in U+03C0 to 192. But this is a moderately difficult mental calculation.

An easier approach would be to leave hex digits alone that correspond to decimal digits, reduce hex digits A through F mod 10, and tack on an extra digit to disambiguate. Stick on a 0, 1, 2, or 3 according to whether no digits, the first digit, the second digit, or both digits had been reduced mod 10. See this page for details. With this system, C0 becomes 201. You could encode 201 as “nest” using the Major system, and imagine a π sitting in a nest, maybe something like the 3Blue1Brown plushie.

3Blue1Brown plushieFor another example, ♕ (U+2655), is the symbol for the white queen in chess. You might think of the White Queen from The Lion, the Witch, and the Wardrobe [2] and associate her with the hex number 0x55. If you convert 0x55 to decimal, you get 85, which you could associate with the Eiffel Tower using the Major system. So maybe imagine the White Queen driving her sleigh under the Eiffel Tower. If you convert 0x55 to 550 as suggested here, you might imagine her driving through a field of lilies.

Often Unicode characters are arranged consecutively in a logical sequence so you can compute the value of the rest of the sequence from knowing the value of the first element. Alphabets are arranged in alphabetical order (mostly [1]), symbols for Roman numerals are arranged in numerical order, symbols for chess pieces are arrange in an order that would make sense to chess players, etc.

[1] There are a few exceptions such as Cyrillic Ё and a gap in Greek capital letters.

[2] She’s not really a queen, but she thinks of herself as a queen. See the book for details.

Redoing images in Midjourney

My son in law was playing around with Midjourney v5 and I asked him to try to redo some of the images I’ve made with DALL-E 2.

Back in August i wrote a post about using DALL-E 2 to generate mnemonic images for memorizing the US presidents using the Major mnemonic system.

To memorize that Rutherford B. Hayes was the 19th president. you might visualize Hayes playing a tuba because you can encode 19 as tuba. The image I created last year was cartoonish and showed Hayes playing something more like a sousaphone than a tuba. Midjourney created a photorealistic image of Hayes playing some weird instrument which is something like a tuba.

Rutherford B. Hayes playing something like a ruba

Franklin Delano Roosevelt was the 32nd president. If we use an image of the moon as the peg for 32, we could imagine FDR looking up at the moon. The previous image of FDR was really creepy and looked nothing like him. The image Midjourney created with FDR was really good.

FDR looking up at the moon

Midjourney choked on the request to create a create an image of Grover Cleveland holding an onion and a wiener dog, just as DALL-E had. It didn’t do any better substituting Grover the Muppet for Grover Cleveland.

A few weeks ago I wrote a blog post about a thought experiment involving an alien astronomer with 12 fingers working in base 12. I could only get DALL-E to draw a hint of an extra finger. We weren’t able to get Midjourney to put 12 fingers on a hand either, but we did get an interesting image of an alien astronomer.

Alien astronomer

Square root mnemonics

Here’s a cute little poem:

I wish I knew
The root of two.

O charmed was he
To know root three.

So we now strive
To find root five.

The beginning of each stanza is a mnemonic for the number mentioned in the following line.

√ 2 = 1.414
√ 3 = 1.732
√ 5 = 2.236

I found this in Twenty Years Before the Blackboard by Michael Stueben. Steuben sites the sources as Dictionary of Mnemonics, London 1972. He doesn’t give any other information such as author or editor.

Update: Additional verse from the comments.

It rhymes with heaven
The root of seven.

Update: Here’s Python code to validate the mnemonics above.

    from math import sqrt

    def validate(line, num):
        digits = [str(len(w)) for w in line.split()]
        x = int("".join(digits)) / 1000
        assert(x == round(sqrt(num),3))

    validate("I wish I knew", 2)
    validate("O charmed was he", 3)
    validate("So we now strive", 5)
    validate("It rhymes with heaven", 7)

Related post: Numbers worth memorizing.