Skip to content

Commit 7a14b97

Browse files
committed
proof: use urkel/proof wrapper.
1 parent 5315651 commit 7a14b97

3 files changed

Lines changed: 96 additions & 173 deletions

File tree

lib/proof.js

Lines changed: 90 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -5,210 +5,142 @@
55
*/
66
'use strict';
77

8-
const assert = require('bsert');
9-
const {proofTypes} = require('./common');
8+
const BLAKE2b = require('./blake2b');
9+
const Proof = require('urkel/lib/proof');
1010

11-
const HASH_SIZE = 32;
1211
const HASH_BITS = 256;
13-
const EMPTY_PROOF = Buffer.alloc(4, 0x00);
1412

15-
class EncodingError extends Error {
16-
/**
17-
* Create an encoding error.
18-
* @constructor
19-
* @param {Number} offset
20-
* @param {String} reason
21-
*/
22-
23-
constructor(offset, reason, start) {
24-
super();
25-
26-
this.type = 'EncodingError';
27-
this.name = 'EncodingError';
28-
this.code = 'ERR_ENCODING';
29-
this.message = `${reason} (offset=${offset}).`;
30-
31-
if (Error.captureStackTrace)
32-
Error.captureStackTrace(this, start || EncodingError);
33-
}
34-
}
35-
36-
class Proof {
13+
class WrappedProof {
3714
constructor() {
38-
this.type = proofTypes.TYPE_UNKNOWN;
39-
this.depth = 0;
40-
this.nodesLen = 0;
41-
this.raw = EMPTY_PROOF;
15+
this._proof = new Proof();
16+
this._raw = null;
17+
this._size = null;
4218
}
4319

44-
getSize() {
45-
return this.raw.length;
20+
get type() {
21+
return this._proof.type;
4622
}
4723

48-
write(data, off) {
49-
checkWrite(off + this.raw.length <= data.length, off);
50-
this.raw.copy(data, off);
51-
return off + this.raw.length;
52-
}
53-
54-
read(data, off) {
55-
assert(Buffer.isBuffer(data));
56-
assert((off >>> 0) === off);
57-
58-
let pos = off;
59-
60-
const field = readU16(data, pos);
61-
pos += 2;
62-
this.type = field >>> 14;
63-
this.depth = field & ~(3 << 14);
64-
65-
if (this.depth > HASH_BITS)
66-
throw new EncodingError(pos, 'Invalid depth');
67-
68-
checkRead(pos + 2 <= data.length, pos);
69-
70-
const count = readU16(data, pos);
71-
const bsize = (count + 7) >>> 3;
72-
pos += 2;
24+
/**
25+
* @returns {Number}
26+
*/
7327

74-
if (count > HASH_BITS)
75-
throw new EncodingError(pos, 'Proof too large');
28+
getSize() {
29+
if (!this._size)
30+
this._size = this._proof.getSize(BLAKE2b, HASH_BITS);
7631

77-
checkRead(pos + bsize <= data.length, pos);
78-
pos += bsize;
32+
return this._size;
33+
}
7934

80-
for (let i = 0; i < count; i++) {
81-
checkRead(pos + 2 <= data.length, pos);
35+
/**
36+
* @param {Buffer} data
37+
* @param {Number} off
38+
* @returns {Number}
39+
*/
8240

83-
if (hasBit(data, (off + 4) * 8 + i))
84-
pos = skipReadBits(data, pos);
41+
write(data, off) {
42+
return this._proof.write(data, off, BLAKE2b, HASH_BITS);
43+
}
8544

86-
pos += HASH_SIZE;
87-
}
45+
/**
46+
* @param {bio.BufferWriter|bio.StaticWriter} bw
47+
* @returns {bio.BufferWriter|bio.StaticWriter}
48+
*/
8849

89-
this.nodesLen = count;
50+
writeBW(bw) {
51+
return this._proof.writeBW(bw, BLAKE2b, HASH_BITS);
52+
}
9053

91-
switch (this.type) {
92-
case proofTypes.TYPE_DEADEND: {
93-
break;
94-
}
54+
/**
55+
* @param {Buffer} data
56+
* @param {Number} off
57+
* @returns {Number}
58+
*/
9559

96-
case proofTypes.TYPE_SHORT: {
97-
pos = skipReadBits(data, pos);
98-
pos += HASH_SIZE;
99-
pos += HASH_SIZE;
100-
break;
101-
}
60+
read(data, off) {
61+
this._proof.read(data, off, BLAKE2b, HASH_BITS);
62+
return this;
63+
}
10264

103-
case proofTypes.TYPE_COLLISION: {
104-
pos += HASH_BITS >>> 3;
105-
pos += HASH_SIZE;
106-
break;
107-
}
65+
/**
66+
* @param {BufferReader} br
67+
* @returns {this}
68+
*/
10869

109-
case proofTypes.TYPE_EXISTS: {
110-
checkRead(pos + 2 <= data.length, pos);
111-
const size = readU16(data, pos);
112-
pos += 2;
113-
pos += size;
70+
readBR(br) {
71+
this._proof.readBR(br, BLAKE2b, HASH_BITS);
72+
return this;
73+
}
11474

115-
break;
116-
}
75+
/**
76+
* @returns {Buffer}
77+
*/
11778

118-
default: {
119-
throw new Error('Invalid type.');
120-
}
121-
}
79+
encode() {
80+
if (!this._raw)
81+
this._raw = this._proof.encode(BLAKE2b, HASH_BITS);
12282

123-
this.raw = data.slice(off, pos);
124-
return pos;
83+
return this._raw;
12584
}
12685

127-
encode() {
128-
return this.raw;
129-
}
86+
/**
87+
* @param {Buffer} data
88+
* @returns {this}
89+
*/
13090

13191
decode(data) {
92+
this._raw = data;
13293
this.read(data, 0);
13394
return this;
13495
}
13596

136-
readBR(br) {
137-
assert(br && typeof br.readU8 === 'function');
138-
br.offset = this.read(br.data, br.offset);
139-
return this;
140-
}
97+
/**
98+
* Verify
99+
* @param {Buffer} root
100+
* @param {Buffer} key
101+
* @returns {Array}
102+
*/
141103

142-
writeBW(bw, hash, bits) {
143-
assert(bw && typeof bw.writeU8 === 'function');
144-
if (bw.data)
145-
bw.offset = this.write(bw.data, bw.offset, hash, bits);
146-
else
147-
bw.writeBytes(this.encode(hash, bits));
148-
return bw;
104+
verify(root, key) {
105+
return this._proof.verify(root, key, BLAKE2b, HASH_BITS);
149106
}
150107

108+
/**
109+
* @param {Buffer} data
110+
* @param {Number} off
111+
* @returns {WrappedProof}
112+
*/
113+
151114
static read(data, off) {
152115
return new this().read(data, off);
153116
}
154117

118+
/**
119+
* @param {BufferReader} br
120+
* @returns {WrappedProof}
121+
*/
122+
155123
static readBR(br) {
156124
return new this().readBR(br);
157125
}
158126

127+
/**
128+
* @param {Buffer} data
129+
* @returns {WrappedProof}
130+
*/
131+
159132
static decode(data) {
160133
return new this().decode(data);
161134
}
162135

136+
/**
137+
* @param {*} obj
138+
* @returns {Boolean}
139+
*/
140+
163141
static isProof(obj) {
164142
return obj instanceof this;
165143
}
166144
}
167145

168-
function skipReadBits(data, off) {
169-
checkRead(off + 2 <= data.length, off);
170-
171-
let size = data[off];
172-
off += 1;
173-
174-
if (size & 0x80) {
175-
size -= 0x80;
176-
size *= 0x100;
177-
size += data[off];
178-
off += 1;
179-
}
180-
181-
const bytes = (size + 7) >>> 3;
182-
183-
checkRead(off + bytes <= data.length, off);
184-
185-
return off + bytes;
186-
}
187-
188-
function hasBit(key, index) {
189-
const oct = index >>> 3;
190-
const bit = index & 7;
191-
return (key[oct] >>> (7 - bit)) & 1;
192-
}
193-
194-
function readU16(data, off) {
195-
return data[off++] + data[off] * 0x100;
196-
}
197-
198-
function checkWrite(ok, offset, start) {
199-
if (!ok) {
200-
throw new EncodingError(offset,
201-
'Out of bounds write',
202-
start || checkWrite);
203-
}
204-
}
205-
206-
function checkRead(ok, offset, start) {
207-
if (!ok) {
208-
throw new EncodingError(offset,
209-
'Out of bounds read',
210-
start || checkRead);
211-
}
212-
}
213-
214-
module.exports = Proof;
146+
module.exports = WrappedProof;

lib/tree.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,8 @@ class Tree {
285285

286286
async prove(key) {
287287
assert(this.isOpen, ERR_NOT_OPEN);
288-
const proof = new Proof();
289288
const raw = await nurkel.tree_prove(this.tree, key);
290-
proof.decode(raw);
291-
return proof;
289+
return Proof.decode(raw);
292290
}
293291

294292
/**
@@ -299,10 +297,8 @@ class Tree {
299297

300298
proveSync(key) {
301299
assert(this.isOpen, ERR_NOT_OPEN);
302-
const proof = new Proof();
303300
const raw = nurkel.tree_prove_sync(this.tree, key);
304-
proof.decode(raw);
305-
return proof;
301+
return Proof.decode(raw);
306302
}
307303

308304
/**
@@ -532,7 +528,7 @@ class Tree {
532528

533529
static async verify(root, key, proof) {
534530
assert(proof instanceof Proof);
535-
return nurkel.verify(root, key, proof.raw);
531+
return nurkel.verify(root, key, proof.encode());
536532
}
537533

538534
/**
@@ -545,7 +541,7 @@ class Tree {
545541

546542
static verifySync(root, key, proof) {
547543
assert(proof instanceof Proof);
548-
return nurkel.verify_sync(root, key, proof.raw);
544+
return nurkel.verify_sync(root, key, proof.encode());
549545
}
550546

551547
/**

lib/urkel.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
const assert = require('bsert');
99
const urkel = require('urkel');
1010
const {Tree} = urkel;
11-
const UrkelProof = urkel.Proof;
1211
const Proof = require('./proof');
1312

1413
const {
@@ -437,9 +436,7 @@ class WrappedTree {
437436
*/
438437

439438
static async verify(root, key, proof) {
440-
const proofobj = UrkelProof.decode(proof.raw, BLAKE2b, BLAKE2b.bits);
441-
const [code, value] = proofobj.verify(root, key, BLAKE2b, BLAKE2b.bits);
442-
return [code, value];
439+
return proof.verify(root, key);
443440
}
444441

445442
/**
@@ -451,9 +448,7 @@ class WrappedTree {
451448
*/
452449

453450
static verifySync(root, key, proof) {
454-
const proofobj = UrkelProof.decode(proof.raw, BLAKE2b, BLAKE2b.bits);
455-
const [code, value] = proofobj.verify(root, key, BLAKE2b, BLAKE2b.bits);
456-
return [code, value];
451+
return proof.verify(root, key);
457452
}
458453

459454
/**

0 commit comments

Comments
 (0)