-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproof.js
executable file
·138 lines (119 loc) · 4.09 KB
/
proof.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env node
const crypto = require('crypto')
const fs = require('fs')
const { fromRpcSig, publicToAddress, ecrecover, hashPersonalMessage } = require('ethereumjs-util')
const Trie = require('merkle-patricia-tree')
const usage = () => {
console.log(`USAGE:
- From file:
$ precedence-proof [FILE]
- From stdin:
$ cat FILE | precedence-proof
`)
process.exit(1)
}
const printResultAndExit = (result) => {
console.log(JSON.stringify(result, null, 2))
process.exit(result.verified ? 0 : 1)
}
const sha256 = value => {
return crypto.createHash('sha256').update(value).digest('hex')
}
(async () => {
if (process.argv.some((arg) => arg === '-h' || arg === '--help')) {
usage()
}
// input from Precedence
let input
if (process.argv.length === 2) {
const timeout = setTimeout(() => {
usage()
}, 100)
input = await new Promise(resolve => {
const chuncks = []
process.stdin.on('data', chunck => {
clearTimeout(timeout)
chuncks.push(chunck)
})
process.stdin.on('end', () => {
resolve(Buffer.concat(chuncks))
})
})
} else if (process.argv.length === 3) {
input = fs.readFileSync(process.argv[2])
} else {
usage()
}
input = JSON.parse(input)
const result = {
WARNING: `Only the date of anchoring of the root block (${input.block.root}) by a trusted tier can be considered as the date of existence of the original document.`,
verified: false,
value: undefined,
message: undefined,
error: undefined
}
// verify that the SHA-256 of the provided data is equal to the provided hash
if (input.data) {
const hash = sha256(Buffer.from(input.data, 'base64'))
if (hash !== input.hash) {
result.error = `The SHA-256 hash of the provided data (${hash}) is not equal to the provided hash (${input.hash}).`
printResultAndExit(result)
}
} else {
result.message = `The original document is not provided, so you must now verify that its SHA-256 hash is equal to ${input.hash}.`
}
// verify that the provided hash is signed
try {
const vrs = fromRpcSig(input.signature)
if ('0x' + publicToAddress(ecrecover(hashPersonalMessage(Buffer.from(input.hash, 'hex')), vrs.v, vrs.r, vrs.s)).toString('hex') !== input.address) {
result.error = 'The provided hash is not signed.'
printResultAndExit(result)
}
} catch (e) {
result.error = `Ethereum signature error: ${e.message}`
printResultAndExit(result)
}
// verify that the SHA-256 hash of '<input.seed> <input.hash>' is equal to the 'input.provable.hash' value
if (sha256(`${input.seed} ${input.hash}`) !== input.provable.hash) {
result.error = `The provided hash (${input.hash}) is not included in the provided provable document.`
printResultAndExit(result)
}
// verify the Merkle Patricia Trie proof, extracting the value
let value
{
// Merkle Patricia Trie root hash
const root = Buffer.from(input.block.root, 'hex')
// Merkle Patricia Trie key
const key = Buffer.from(input.provable.id, 'hex')
// Merkle Patricia Trie prove
const proof = input.block.proof.map(hex => Buffer.from(hex, 'hex'))
try {
value = await new Promise((resolve, reject) => {
try {
Trie.verifyProof(root, key, proof, (error, value) => {
if (error) {
return reject(error)
}
resolve(value.toString('hex'))
})
} catch (e) {
reject(e)
}
})
} catch (e) {
result.error = `Merkle Patricia Trie error: ${e.message}`
printResultAndExit(result)
}
}
// verify that the extracted value from the proof is equal to the SHA-256 hash of the provided provable document
const expectedValue = sha256(JSON.stringify(input.provable))
if (value !== expectedValue) {
result.error = `The value extracted from the proof (${value}) is not equal to the SHA-256 hash of the provided provable document (${expectedValue})`
printResultAndExit(result)
}
// verified!
result.verified = true
printResultAndExit(result)
})().catch(e => {
console.error(e)
})