Re: [Trans] Verifying inclusion proof

Adam Eijdenberg <eijdenberg@google.com> Fri, 26 June 2015 16:02 UTC

Return-Path: <eijdenberg@google.com>
X-Original-To: trans@ietfa.amsl.com
Delivered-To: trans@ietfa.amsl.com
Received: from localhost (ietfa.amsl.com [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 688AF1A888E for <trans@ietfa.amsl.com>; Fri, 26 Jun 2015 09:02:35 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.388
X-Spam-Level:
X-Spam-Status: No, score=-1.388 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FM_FORGED_GMAIL=0.622, HTML_MESSAGE=0.001, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01] autolearn=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ahBGov4QygXI for <trans@ietfa.amsl.com>; Fri, 26 Jun 2015 09:02:33 -0700 (PDT)
Received: from mail-yk0-x234.google.com (mail-yk0-x234.google.com [IPv6:2607:f8b0:4002:c07::234]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 6807D1A88A6 for <trans@ietf.org>; Fri, 26 Jun 2015 09:02:32 -0700 (PDT)
Received: by ykdr198 with SMTP id r198so62383060ykd.3 for <trans@ietf.org>; Fri, 26 Jun 2015 09:02:31 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :content-type; bh=rcJix56m666U/oGL+Ep7uxWmHMsgjWYiGV8nsO8hBEs=; b=aU4sjBmPF2u9roGBidEM28314jPxP6k4LgVBSdjn5BW4Zuc/Fs144A4ZXYhnljctEy 3di9N2JCky+SO4O4rwkFzpDux6vnYLqsPXk4bGNSYMExtcOMwEYDRUk2AaVnx6fak5LR C8nnwG03PFCcVtbcTmLxkM/KianCIqnyhrFg/KFUl3osHS3qXi6MA/7svCqocJPH7E1g hIcuBZQuSay9io3I3uJrqgoQAnxx6qiooig6m+3wbbaGw8PCwmpCmQNaB30VOXVqDDZq +G/7MKGX0repUmLnGNPDvTjnNMgcwVOuUN0M4VfV5tkhUREI7sDo8viXKdMTs23ohACZ uJ4w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:content-type; bh=rcJix56m666U/oGL+Ep7uxWmHMsgjWYiGV8nsO8hBEs=; b=RQ7LQ6CZ8kwotgf1OpCCo/9l9iOr1TOsmVIJJ+vPS2poVTL5osGkJff83/PEc9qGy1 XZz2RMiHHgfhf5sOi+9q4CB8P9mfrlKu6skxCB1tIhzGKPQz9uF2tOx9uf1hDsYjpNwA epDNYa50ldQPwLZzO/T3daRmWQ5gdhxCgQOhqxFZjSUFI0CTGZAU2bHujaY1GYvRm40h g4gru0o383AmUs6aT+Oz9mwA10UdXi3RS13XQw0fUAUKi6SJg3fXdJGmFUZB0YsDgeWE DxxXliePlpTKlOIQKzTl1ZtMwIq3oFJSF68r1Rp1wT0FsDknHtii7X8S6LUbws0LYVa0 z/xg==
X-Gm-Message-State: ALoCoQnNgnpJ0frsCt8uPYfGqE7T5IXaByA7ONIltISoYjEig5OtpIeF1Z+pMhGcr4BzVq/wNrv/
X-Received: by 10.129.32.4 with SMTP id g4mr3014179ywg.94.1435334551702; Fri, 26 Jun 2015 09:02:31 -0700 (PDT)
MIME-Version: 1.0
References: <558D61DE.8020402@nic.cz>
In-Reply-To: <558D61DE.8020402@nic.cz>
From: Adam Eijdenberg <eijdenberg@google.com>
Date: Fri, 26 Jun 2015 16:02:22 +0000
Message-ID: <CAP9QY5ZpX00Smzk-Ghj8VP4Nfa8pVaJKEJ4wCcUnFwOmf7XfGA@mail.gmail.com>
To: Ondrej Mikle <ondrej.mikle@nic.cz>, trans@ietf.org
Content-Type: multipart/alternative; boundary="001a1141384c16b3b805196dde49"
Archived-At: <http://mailarchive.ietf.org/arch/msg/trans/jh4us1FkEPCp8mSlrnkWfwYmaXI>
Subject: Re: [Trans] Verifying inclusion proof
X-BeenThere: trans@ietf.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: Public Notary Transparency working group discussion list <trans.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/trans>, <mailto:trans-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/trans/>
List-Post: <mailto:trans@ietf.org>
List-Help: <mailto:trans-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/trans>, <mailto:trans-request@ietf.org?subject=subscribe>
X-List-Received-Date: Fri, 26 Jun 2015 16:02:35 -0000

Hi Ondrej,

I had the exact same question last week when I started wanted to verify
get-proof-by-hash.  It turns out that you actually can figure out which is
applied to the left and the right by looking the bits in the index of the
log entry that you are requesting proof for.  I found it easier to describe
in code than words.  Take a look at the following Python that fetches an
arbitrary entry from an arbitrary log, then fetches the current STH, then
requests an inclusion proof and finally verifies that proof.

I hope that helps.

Cheers, Adam


import urllib, urllib2, json, base64, hashlib

# Entry to play with
log_entry = 438942
log = 'ct.googleapis.com/pilot'

# Get the merkle tree leaf and b64 decode it
entries = json.loads(urllib2.urlopen('https://%s/ct/v1/get-entries?%s' %
(log, urllib.urlencode({'start': log_entry, 'end': log_entry}))).read())
mtl = base64.b64decode(entries['entries'][0]['leaf_input'])

# Get current STH
sth = json.loads(urllib2.urlopen('https://%s/ct/v1/get-sth' % log).read())

# Create the leaf hash
leaf_hash = hashlib.sha256(chr(0) + mtl).digest()

# Fetch proof that the leaft hash is included in the current STH
url = 'https://%s/ct/v1/get-proof-by-hash?%s' % (log,
urllib.urlencode({'hash': base64.b64encode(leaf_hash), 'tree_size':
sth['tree_size']}))
proof = json.loads(urllib2.urlopen(url).read())

# Derive the sha256 root hash based on the leaf_hash and the audit_proof
node = leaf_hash
idx = log_entry
for p in proof['audit_path']:
  if idx & 1:
    node = hashlib.sha256(chr(1) + base64.b64decode(p) + node).digest()
  else:
    node = hashlib.sha256(chr(1) + node + base64.b64decode(p)).digest()
  idx >>= 1

if node == base64.b64decode(sth['sha256_root_hash']):
  print 'Log proved inclusion'
else:
  print 'Fail.'



On Fri, Jun 26, 2015 at 7:30 AM Ondrej Mikle <ondrej.mikle@nic.cz> wrote:

> Pardon me if I am asking something obvious, but I'm missing one piece of
> information for inclusion proof verification - the "placement" of each
> node returned from "get-proof-by-hash" method in audit_path list
> (whether it's left subtree or right subtree).
>
> Since the hashing of concatenation of strings is not commutative, the
> auditor needs to put the two partial tree hashes in correct order to get
> to the correct root hash.
>
> I'd guess the placement of the missing nodes from audit_path could be
> derived from leaf_index and tree_size, but can't see a straightforward
> way to do it. The reference client does not implement this verification
> either.
>
> Ondrej
>
> _______________________________________________
> Trans mailing list
> Trans@ietf.org
> https://www.ietf.org/mailman/listinfo/trans
>