No Such lAbs releases V for Victory.

Monday, 31 August, Year 7 d.Tr. | Author: Mircea Popescu

The idea behind this is discussed in an older post to the Bitcoin Foundation's mailing list :

The V-genesis patch is a most important milestone in the evolution of computer programming, from its troglodyte state prior to the involvement of The Most Serene Republic, towards its civilised state as you enjoy it today.

For the first time in the century or so of history of this particular human endeavour, text was deliberately structured with due consideration given not only to its meaning, but also to its source, and to its context. Prior attempts at structuring software, at first consisting of a naive approach focused on meaning only, over time added a half-hearted consideration of context, very unequally and rather haphazardly. The change the V-genesis introduced is exactly like the move from understanding and controlling movement in terms of mass and somewhat velocity, such as it occurs in the mind of a monkey throwing rocks, to understanding and controlling movement in terms of mass, impulse and energy, such as it occurs in the launching of satellites. The proposition that there is still room for improvement in the endless march of human thought, on this topic as on any other, is absolutely indubitable. The proposition that the sum total of what came before can be compared with this particular advance is strictly ridiculous.

Used together with specialised scripts, V-genesis allows an agent to reconstruct a complete Bitcoin tree, verify its correctness, and manage his investment of trust at all junctures so that he is never required to implicitly trust either an unknown code author, or a code snippet of unknown provenance.

There remains after today no alternative manner to deploy Bitcoin software, or indeed any software that is not a toy intended to be used by children playing, outside of this paradigm. May the switchover be bloody and painful in all the right places.

The engine of the entire thing is quoted below, for your viewing pleasure :

#!/usr/bin/python

##############################################################################
# Quick Intro:
# 1) Create '.wot' in your home directory. Fill it with public keys from 'wot'.
# 2) Create '.seals' in your home directory. Place all signatures there from
'sigs'.
# 3) Create a 'patches' directory somewhere where 'v' can find it. Or use this
one.
# 4) ./v.py patches command
# e.g.,
# ./v.py patches w
#                  ^^ displays WoT
#  ./v.py patches p patches/asciilifeform_add_verifyall_option.vpatch
asciis_bleedingedge
#                  ^^ this 'presses' (creates the actual tree)
#                  ^^ approximately like a 'checkout' in your vanilla flavoured
shithub.

##############################################################################

import os, sys, shutil, argparse, re, tempfile, gnupg

##############################################################################
vver = 100 # This program's Kelvin versioni.

## HOW YOU CAN HELP: ##

# * TESTS plox, ty!
#
# Report findings in #bitcoin-assets on Freenode.

##############################################################################

prolog =  '''\
(C) 2015 NoSuchlAbs.
You do not have, nor can you ever acquire the right to use, copy or distribute
this software ;
Should you use this software for any purpose, or copy and distribute it to
anyone or in any manner, you are breaking the laws of whatever soi-disant
jurisdiction, and you promise to continue doing so for the indefinite future.
In any case, please always : read and understand any software ; verify any PGP
signatures that you use - for any purpose.
'''

intro = "V (ver. {0}K)\n".format(vver)

##############################################################################
def toposort(unsorted):
    sorted = []
    unsorted = dict(unsorted)
    while unsorted:
        acyclic = False
        for node, edges in unsorted.items():
            for edge in edges:
                if edge in unsorted:
                    break
            else:
                acyclic = True
                del unsorted[node]
                sorted.append((node, edges))
        if not acyclic:
            fatal("Cyclic graph!")
    return sorted
##############################################################################

verbose = False

def fatal(msg):
    sys.stderr.write(msg + "\n")
    exit(1)

def spew(msg):
    if verbose:
        print msg

# List of files in a directory, in lexical order.
def dir_files(dir):
    return sorted([os.path.join(dir, fn) for fn in next(os.walk(dir))[2]])

# GPG is retarded and insists on 'keychain.'
# This will be a temp dir, because we don't do any crypto.
gpgtmp = tempfile.mkdtemp()
gpg = gnupg.GPG(gnupghome=gpgtmp)
gpg.encoding = 'utf-8'

# Known WoT public keys.
pubkeys = {}

# The subset of vpatches that are considered valid.
patches = []

# Banners (i.e. vpatches mapped to their guarantors)
banners = {}

# Roots (i.e. vpatches parented by thin air)
roots = []

# Table mapping file hash to originating vpatch
desc = {}
desc['false'] = 'false'

# Grep for diff magics, and memoize
def vpdata(path, exp, cache):
    l = cache.get(path)
    if not l:
        l = []
        patch = open(path, 'r').read()
        for m in re.findall(exp, patch, re.MULTILINE):
            l += [{'p':m[0], 'h':m[1]}]
        cache[path] = l
    return l

# Get parents of a vpatch
pcache = {}
def parents(vpatch):
    parents = vpdata(vpatch, r'^--- (\S+) (\S+)$', pcache)
    if not parents:
        fatal("{0} is INVALID, check whether it IS a vpatch!".format(vpatch))
    return parents

# Get children of a vpatch
ccache = {}
def children(vpatch):
    children = vpdata(vpatch, r'^\+\+\+ (\S+) (\S+)$', ccache)
    if not children:
        fatal("{0} is INVALID, check whether it IS a vpatch!".format(vpatch))
    # Record descendents:
    for child in children:
        h = child['h']
        if h != 'false':
            desc[h] = vpatch
    return children

# It is entirely possible to have more than one root!
# ... exactly how, is left as an exercise for readers.
def find_roots(patchset):
    rset = []
    # Walk, find roots
    for p in patchset:
        if all(p['h'] == 'false' for p in parents(p)):
            rset += [p]
            spew("Found a Root: '{0}'".format(p))
    return rset

# Get antecedents.
def get_ante(vpatch):
    ante = {}
    for p in parents(vpatch):
        pp = desc.get(p['h']) # Patch where this appears
        if not ante.get(pp):
            ante[pp] = []
        ante[pp] += [p['p']]
    return ante

# Get descendants.
def get_desc(vpatch):
    des = {}
    for p in patches:
        ante = get_ante(p)
        if vpatch in ante.keys():
            des[p] = ante[vpatch]
    return des

##############################################################################

# Print name of patch and its guarantors, or 'WILD' if none known.
def disp_vp(vpatch):
    seals = ', '.join(map(str, banners[vpatch]))
    if seals == '':
        seals = 'WILD'
    return "{0} ({1})".format(vpatch, seals)

##############################################################################

# Command: WoT
def c_wot(args):
    for k in pubkeys.values():
        print "{0}:{1} ({2})".format(k['handle'], k['fp'], k['id'])

# Command: Flow
def c_flow(args):
    for p in patches:
        print disp_vp(p)

# Command: Roots.
def c_roots(args):
    for r in roots:
        print "Root: " + disp_vp(r)

# Command: Antecedents.
def c_ante(args):
    ante = get_ante(args.query)
    for p in ante.keys():
        if p != 'false':
            print "{0} [{1}]".format(disp_vp(p), '; '.join(map(str, ante[p])))

# Command: Descendants
def c_desc(args):
    des = get_desc(args.query)
    for d in des.keys():
        print "Descendant: {0} [{1}]".format(disp_vp(d), '; '.join(map(str,
des[d])))

# Command: Press.
def c_press(args):
    print "Pressing using head: {0} to path: '{1}'".format(args.head, args.dest)
    headpos = patches.index(args.head)
    seq = patches[:headpos + 1]
    os.mkdir(args.dest)
    for p in seq:
        print "Using: {0}".format(disp_vp(p))
        os.system("patch -E --dir {0} -p1 < {1}".format(args.dest, p))
    print "Completed Pressing using head: {0} to path: '{1}'".format(args.head,
args.dest)

# Command: Origin.
def c_origin(args):
    o = desc.get(args.query)
    if o:
        print disp_vp(o)
    else:
        print "No origin known."

##############################################################################

##############################################################################
# Command line parameter processor.
parser = argparse.ArgumentParser(description=intro, epilog=prolog)

# Print paths, etc
parser.add_argument('-v', dest='verbose', default=False,
                    action="store_true", help='Verbose.')

# Permit the use of patches no one has yet sealed. Use this ONLY for own dev
work!
parser.add_argument('-wild', dest='wild', default=False,
                    action="store_true", help='Permit wild (UNSEALED!)
vpatches.')

# Glom keyid (short fingerprint) onto every WoT handle.
parser.add_argument('-fingers', dest='fingers', default=False,
                    action="store_true", help='Prefix keyid to all WoT
handles.')

# Default path of WoT public keys is /home/yourusername/.wot
# This dir must exist. Alternatively, you may specify another.
parser.add_argument('--wot', dest='wot',
default=os.path.join(os.path.expanduser('~'), '.wot'),
                    action="store", help='Use WoT in given directory. (Default:
~/.wot)')

# Default path of the seals (PGP signatures) is /home/yourusername/.seals
# This dir must exist. Alternatively, you may specify another.
parser.add_argument('--seals', dest='seals',
default=os.path.join(os.path.expanduser('~'), '.seals'),
                    action="store", help='Use Seals in given directory.
(Default: ~/.seals)')

# REQUIRED: Path of directory with vpatches.
parser.add_argument('vpatches', help='Vpatch directory to operate on.
[REQUIRED]')

# REQUIRED: Command.
subparsers = parser.add_subparsers(help='Command [REQUIRED]')

parser_w = subparsers.add_parser('w', help='Display WoT.')
parser_w.set_defaults(f=c_wot)

parser_r = subparsers.add_parser('r', help='Display Roots.')
parser_r.set_defaults(f=c_roots)

parser_a = subparsers.add_parser('a', help='Display Antecedents [PATCH]')
parser_a.set_defaults(f=c_ante)
parser_a.add_argument('query', action="store", help='Patch.')

parser_d = subparsers.add_parser('d', help='Display Descendants [PATCH]')
parser_d.set_defaults(f=c_desc)
parser_d.add_argument('query', action="store", help='Patch.')

parser_l = subparsers.add_parser('f', help='Compute Flow.')
parser_l.set_defaults(f=c_flow)

parser_p = subparsers.add_parser('p', help='Press [HEADPATCH AND DESTINATION]')
parser_p.set_defaults(f=c_press)
parser_p.add_argument('head', action="store", help='Head patch.')
parser_p.add_argument('dest', action="store", help='Destionation directory.')

parser_o = subparsers.add_parser('o', help='Find Origin [SHA512]')
parser_o.set_defaults(f=c_origin)
parser_o.add_argument('query', action="store", help='SHA512 to search for.')

##############################################################################

# V cannot operate without vpatches, WoT, and Seals datasets.
def reqdir(path):
    if (not (os.path.isdir(path))):
        fatal("Directory '{0}' does not exist!".format(path))
    return path

def main():
    global verbose, pubkeys, patches, roots, banners

    args = parser.parse_args()
    verbose = args.verbose

    # Patch and Sigs dirs
    pdir = reqdir(args.vpatches)
    sdir = reqdir(args.seals)
    wdir = reqdir(args.wot)

    spew("Using patches from:" + pdir)
    spew("Using signatures from:" + sdir)
    spew("Using wot from:" + wdir)

    pfiles = dir_files(pdir)
    sfiles = dir_files(sdir)
    wfiles = dir_files(wdir)

    # Build WoT from pubkeys
    handle = {}
    for w in wfiles:
        pubkey = open(w, 'r').read()
        impkey = gpg.import_keys(pubkey)
        for fp in impkey.fingerprints:
            handle[fp] = os.path.splitext(os.path.basename(w))[0]

    for k in gpg.list_keys():
        name = handle[k['fingerprint']]
        if args.fingers:
            name += '-' + k['keyid']
        pubkeys[k['keyid']] = {'fp':k['fingerprint'],
                               'id':', '.join(map(str, k['uids'])),
                               'handle':name}

    # Validate seals
    for p in pfiles:
        pt = os.path.basename(p)
        banners[p] = []
        for s in sfiles:
            sig = os.path.basename(s)
            # All seals must take the form patchtitle.vpatch.yourname.sig
            if sig.find(pt) == 0: # substring of sig filename up through
'.vpatch'
                v = gpg.verify_file(open(s, 'r'), data_filename=p)
                if v.valid:
                    banners[p] += [pubkeys[v.key_id]['handle']]
                else:

fatal("---------------------------------------------------------------------\n"
+
                          "WARNING: {0} is an INVALID seal for {1}
!\n".format(sig, pt) +
                          "Check that this user is in your WoT, and that this
key has not expired.\n" +
                          "Otherwise remove the invalid seal from your SEALS
directory.\n" +

"---------------------------------------------------------------------")

    # Select the subset of vpatches currently in use.
    for p in pfiles:
        if banners.get(p) or args.wild:
            patches += [p]
            children(p) # Memoize.
            parents(p) # Memoize.

    roots = find_roots(patches)
    if not roots:
        fatal('No roots found!')

    # Topological ordering of flow graph
    l = []
    for p in patches:
        l += [(p, get_desc(p).keys())]
    s = map(lambda x:x[0], toposort(l))
    patches = s[::-1]

    # Run command
    args.f(args)

    # Remove temporary keychain
    shutil.rmtree(gpgtmp)

##############################################################################

if __name__ == '__main__' :
    main()

##############################################################################

The whole shebang is available either from the aforementioned mailing list, or directly hereii. Congrats to Stan for his tireless effectuality, and always remember :

Learn the code ; for the code will set you free.

PS. The only thing this needs in terms of packages is 'python-gnupg'.iii

———
  1. Quoth Knuth (TUGboat, Volume 11/1990, No. 4) :
    The current version number for TEX is 3.1, and for METAFONT it is 2.7. If corrections are necessary, the next versions of TEX will be 3.14, then 3.141. then 3.1415. . . . , converging to the ratio of a circle's circumference to its diameter; for METAFONT the sequence will be 2.71. 2.718, . . . , converging to the base of natural logarithms. I intend to be fully responsible for all changes to these systems for the rest of my life. I will periodically study reports of apparent bugs, and I will decide whether changes need to be made. Rewards will be paid to the first finders of any true bugs, at my discretion. but I can no longer afford to double the size of the reward each year. Whenever I have created a new version, I will put it in the official master T archive which currently resides at Stanford University. At the time of my death, it is my intention that the then-current versions of 7&X and METAFONT be forever left unchanged, except that the final version numbers to be reported in the "banner" lines of the programs should become TeX, Version $\pi$ and METAFONT, Version $e$ respectively. From that moment on, all "bugs" will be permanent "features."
    The man knew what he was doing. Unlike virtually anyone "involved" in computing then, or hence. []
  2. Since Automattic is a pile of imbeciles, should you wish to use this you'll have to rename the file to .tar.gz. []
  3. Notably NOT 'gnupg'. If you have that one installed it will croak. []
Category: S.NSA
Comments feed : RSS 2.0. Leave your own comment below, or send a trackback.

9 Responses

  1. [...] republican versioning control system, V for Victory, is very much used, very much needed but nevertheless not yet versioned itself. As this has caused [...]

  2. [...] references: V for Victory V-tronics 101 A collection of vpatch trees, for example, can be seen at btcbase.org/patches. Have [...]

  3. [...] home cooking computing paradigm has been the only tenable method of sane computer operation since 2015 and will remain the case moving forward. The tools and training we provide clients accelerate their [...]

  4. [...] Recall [V]ictory [...]

  5. [...] (2015). TMSR's official versioning system, making everything that happened before in computing look almost as dumb as it [...]

  6. [...] No Such lAbs releases V for Victory. [...]

  7. [...] of the matter, and perhaps even my approach to gaining understanding, needed some fixing too.(i) In short, it's nearsighted to define V as an improved kind of version control system; rather, its [...]

  8. [...] also first-hand experience with all the different ways in which *all* implementations of V so far (v.py, v.pl, v.sh & vtools) fail in practice as soon as applied to any production code base with all [...]

  9. [...] with glaring inadequacy in [the shockingly, vanishingly little that's] leftover [of erstwhile] republican infrastructure : a very angry engineer reported that she's now stuck going through and reviewing [...]

Add your cents! »
    If this is your first comment, it will wait to be approved. This usually takes a few hours. Subsequent comments are not delayed.