@tzstamp/proof
v0.3.4
Published
Cryptographic proofs for TzStamp tools
Downloads
14
Keywords
Readme
TzStamp Proofs
Cryptographic timestamp proofs for use with TzStamp tools.
TzStamp's proof protocol works by:
- Constructing a local Merkle tree of user submitted hashes.
- Publishing the root of that tree in a Tezos blockchain transaction.
- Constructing a chain of commitments starting from the local Merkle leaves up to the hash of the Tezos block containing the transaction.
The use of a local Merkle tree allows users to verify their proofs without storing many unrelated hashes or relying on a central server. Tezos uses its own Merkle Tree structure internally for operations and blocks. TzStamp 'bridges' its local Merkle Tree with the on-chain tree by deriving a chain of commitments between them. The chain of commitments approach lets TzStamp proofs avoid relying on indexers. This is useful both for internal development reasons (at time of writing Tezos indexers don't share a standard API) and for reducing the attack surface of the overall TzStamp system. Leveraging the Tezos Merkle Trees in this way also lets the smart contract used for publishing hashes avoid storing any data at all. Instead a no-op function accepting the hash as an argument can be called. The resulting operation will stay in node archives long enough for TzStamp to bridge its local tree root with the on-chain Merkle Tree. At that point the proof is no longer reliant on Tezos nodes keeping a copy of the operation at all, so it doesn't concern a TzStamp instance if the nodes garbage collect it.
Usage
// Node + NPM
const {/*...*/} = require("@tzstamp/proof");
// Deno
import {/*...*/} from "https://raw.githubusercontent.com/marigold-dev/tzstamp/0.3.4/proof/mod.ts";
See the full reference documentation here.
Constructing a proof
Build an array of operations for the proof:
const {
Sha256Operation,
Blake2bOperation,
JoinOperation,
} = require("@tzstamp/proof");
// Create operations
const operations = [
// Hash operations
new Sha256Operation(),
new Blake2bOperation(32),
new Blake2bOperation(64, myKey),
// Join operations
new JoinOperation({ prepend: uint8Array }),
new JoinOperation({ append: uint8Array }),
];
Create a proof:
const { Proof } = require("@tzstamp/proof");
// Proof segment
const proof = Proof.create({
hash: myInputHash, // Uint8Array
operations,
}); // Proof{}
// Proof affixed to the Tezos blockchain
// The derivation of this proof is taken to be a raw Tezos block hash.
const affixedProof = Proof.create({
hash: myInputHash,
operations,
network: "NetXdQprcVkpaWU", // Tezos network identifier
timestamp: new Date("1970-01-01T00:00:00.000Z"), // Timestamp asserted by proof
}); // AffixedProof{}
// Remote resolvable proof
// The proof is to be concatenated with the proof segment published at the remote address
const unresolvedProof = Proof.create({
hash: myInputHash,
operations: [...],
remote: "https://tzstamp.example.com/proof/...",
}); // UnresolvedProof{}
Verifying affixed proofs
Affixed proofs (AffixedProof
subclass) may be verified against a Tezos RPC.
if (proof.isAffixed()) {
proof.blockHash; // Base58 encoded block hash
proof.mainnet; // Indicates that the affixed network is the Tezos Mainnet
const result = await proof.verify(rpcURL);
// Ex:
// VerifyResult { verified: false, status: "notFound", message: "Derived block could not be found"}
// VerifyResult { verified: true, status: "verified", message: "Verified proof" }
}
Concatenating proof segments
Long proofs may be constructed in segments and concatenated. Concatenation is only possible if the derivation of the first proof (the output of each operation applied to its input hash) matched the input hash of the second proof.
const proofA = Proof.create({
hash: inputHash,
operations: [/*...*/],
});
const proofB = Proof.create({
hash: midHash,
operations: [/*...*/],
});
const proofAB = proofA.concat(proofB); // Throws if `proofA.derivation` is not equal to `proofB.hash`
Resolving unresolved proofs
Unresolved proofs (UnresolvedProof
subclass) may be resolved by fetching the
next proof segment from a remote server and concatenating.
if (proof.isUnresolved()) {
const fullProof = await proof.resolve();
}
Serializing and Deserializing
Note: The tzstamp-proof
v0.3.0 release supports version 1 proof templates.
Use the tzstamp-proof
v0.1.0 release for version 0 proof templates, and the
Demo releases for pre-version proof templates.
// Deserialize from JSON
const json = fs.readFileSync("my-proof.json", "utf-8");
const proof = Proof.from(json);
// Serialize to JSON
const json = JSON.stringify(proof);
fs.writeFileSync("my-proof.json", json);