Last active
June 9, 2020 05:44
-
-
Save 0xankit/25505cee9634fa7e9ed147d15b36363f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run with command: node Differential.js | |
/* | |
This experiment aims to measure the percentage of users on the internet who are actually dogs. | |
Real dogs would like to remain anonymous. After all, on the internet nobody knows you're a dog. | |
*/ | |
// real (secret) populations | |
let numPeople = 90; | |
let numDogs = 10; | |
// TIP! try making the populations larger. What happens to the accuracy of the | |
// differentially-private estimate when we do? | |
const bigPopulation = false; | |
if (bigPopulation) { | |
numPeople *= 10000; | |
numDogs *= 10000; | |
} | |
// answer returns a differentially-private answer to the question "Are you a dog?". Takes `realDog` | |
// as input, depending on whether the user answering the question is truly a dog. | |
function answer(realDog) { | |
if (Math.random() < .5) { | |
// answer truthfully | |
return realDog; | |
} | |
// answer randomly | |
return Math.random() < .5; | |
} | |
// total counts the number of responses to the question "Are you a dog?". Some respondents are | |
// telling the truth, other are not | |
let total = 0; | |
// ask all the dogs | |
for (let i = 0; i < numDogs; i++) { | |
if (answer(true)) { total++; } | |
} | |
// ask all the people | |
for (let i = 0; i < numPeople; i++) { | |
if (answer(false)) { total++; } | |
} | |
// 50% of the answers are true. The other 50% have a 50% probability of being true, and a 50% probability of being false | |
const estimate = 2 * (total / (numPeople+numDogs) - .25); | |
(2 * total)/(numPeople+numDogs) - .25; | |
(total)/(numPeople) - .25; | |
function percentage(x) { | |
return (100 * x).toFixed(2) + '%'; | |
} | |
console.log(`The actual percentage of dogs on the internet: ${percentage(numDogs/(numPeople+numDogs))}`); | |
console.log(`Differentially-private estimate of dogs on the internet: ${percentage(estimate)}`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// npm install js-sha256 | |
// Run with command: node hash.js | |
const sha256 = require('js-sha256'); // npm install js-sha256 | |
/* | |
Alice has created a will (legal document) detailing how she would like to distribute her personal assets | |
upon her death. She wants to record this information to the blockchain for safety, but does not want to | |
reveal her net work or account addresses to the public. To do this she computes the SHA256 hash of her | |
document, records the hash to the blockchain and sends the complete document to Bob, her heir. | |
*/ | |
/* | |
The super secret document! | |
*/ | |
const document = 'Give 50 BTC from my wallet 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa to Bob'; | |
/* | |
Alice computes the hash of her document | |
*/ | |
const hash = sha256(document); // Result: 4f09ccb54e3074d49bb745d923fcc810e88181c241560b5499bc07919ed30ea7 | |
console.log(`Alice hashes her document and records the following hash value to the blockchain: ${hash}`); | |
/* | |
Bob receives a document, which purports to be from Alice. He can compare the document to the hash by | |
computing the received document's SHA256 and verifying it matches the value he obtains from the blockchain | |
*/ | |
if (sha256(document) === hash) { | |
console.log('Document is legit 👍'); | |
} else { | |
console.log("Whoa! That's a fake document"); | |
} | |
/* | |
Suppose instead that Bob's sister Eve wanted to inherit Alice's bitcoins, and she distributes a forged will. | |
Alice and Bob can still communicate with all the reliability as if she'd publicly written her will to the | |
blockchain itself | |
*/ | |
const fake = 'Give 50 BTC from my wallet 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa to Eve'; | |
if (sha256(fake) === hash) { | |
console.log('Document is legit 👍'); | |
} else { | |
console.log("Whoa! That's a fake document"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.24; | |
// Define a contract 'Lemonade Stand' | |
contract LemonadeStand { | |
// Variable: Owner | |
address owner; | |
// Variable: SKU count | |
uint skuCount; | |
// Event: 'State' with value 'ForSale' | |
enum State { ForSale, Sold, shipped } | |
// Struct: Item. name, sku, price, state, seller, buyer | |
struct Item { | |
string name; | |
uint sku; | |
uint price; | |
State state; | |
address seller; | |
address buyer; | |
} | |
// Define a public mapping 'items' that maps the SKU (a number) to an Item. | |
mapping (uint => Item) items; | |
// Events | |
event ForSale(uint skuCount); | |
event Sold(uint sku); | |
event shipped(uint sku); | |
// Modifier: Only Owner see if msg.sender == owner of the contract | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
// Define a modifier that verifies the Caller | |
modifier verifyCaller (address _address) { | |
require(msg.sender == _address); | |
_; | |
} | |
// Define a modifier that checks if the paid amount is sufficient to cover the price | |
modifier paidEnough(uint _price) { | |
require(msg.value >= _price); | |
_; | |
} | |
// Define a modifier that checks if an item.state of a sku is ForSale | |
modifier forSale(uint _sku) { | |
require(items[_sku].state == State.ForSale); | |
_; | |
} | |
// Define a modifier that checks if an item.state of a sku is Sold | |
modifier sold(uint _sku) { | |
require(items[_sku].state == State.Sold); | |
_; | |
} | |
modifier checkValue(uint _sku) { | |
_; | |
uint _price = items[_sku].price; | |
uint amountToRefund = msg.value - _price; | |
items[_sku].buyer.transfer(amountToRefund); | |
} | |
constructor() public payable { | |
owner = msg.sender; | |
skuCount = 0; | |
} | |
function addItem(string _name, uint _price) onlyOwner public { | |
// Increment sku | |
skuCount = skuCount + 1; | |
// Emit the appropriate event | |
emit ForSale(skuCount); | |
// Add the new item into inventory and mark it for sale | |
items[skuCount] = Item({name: _name, sku: skuCount, price: _price, state: State.ForSale, seller: msg.sender, buyer: 0}); | |
} | |
function buyItem(uint sku) forSale(sku) paidEnough(items[sku].price) checkValue(sku) public payable { | |
address buyer = msg.sender; | |
uint price = items[sku].price; | |
// Update Buyer | |
items[sku].buyer = buyer; | |
// Update State | |
items[sku].state = State.Sold; | |
// Transfer money to seller | |
items[sku].seller.transfer(price); | |
// Emit the appropriate event | |
emit Sold(sku); | |
} | |
function shipItem(uint _sku) public onlyOwner sold(_sku){ | |
items[_sku].state = State.shipped; | |
emit shipped(_sku); | |
} | |
function fetchItem(uint _sku) public view returns (string name, uint sku, uint price, string stateIs, address seller, address buyer) { | |
uint state; | |
name = items[_sku].name; | |
sku = items[_sku].sku; | |
price = items[_sku].price; | |
state = uint(items[_sku].state); | |
if( state == 0) { | |
stateIs = "For Sale"; | |
} | |
if( state == 1) { | |
stateIs = "Sold"; | |
} | |
seller = items[_sku].seller; | |
buyer = items[_sku].buyer; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// npm install js-sha256 | |
// Run with command: node Merkle.js | |
const sha256 = require('js-sha256'); | |
function MerkleTree(vals) { | |
// hash values and add to leaves of tree | |
const hashes = []; | |
hashes.push(vals.map(v => sha256(''+v))); | |
// add hash parents as until they converge to a single root | |
for (let last = hashes[hashes.length - 1]; last.length > 1; last = hashes[hashes.length - 1]) { | |
// calc next level of hashes and add to tree | |
hashes.push(parents(last)); | |
} | |
this.__hashes = hashes; | |
} | |
// parents is a helper function for the MerkleTree constructor. It combines | |
// child values and hashes them to create parent values for one generation of | |
// children | |
function parents(children) { | |
const parents = []; | |
// step through children 2 by 2. Designate the first child the "left" child | |
// and the (optional) second child the "right" child | |
for (let i = 0; i < children.length; i += 2) { | |
const left = children[i]; | |
// is children array has odd length, double the last child | |
const right = children.length > i+1 ? children[i+1] : children[i]; | |
parents.push(sha256(left+right)); | |
} | |
return parents; | |
} | |
// root returns the root of the Merkle tree | |
MerkleTree.prototype.root = function() { | |
return this.__hashes[this.__hashes.length - 1][0]; | |
} | |
// proof returns the hashes along a single branch of the Merkle tree, aka the | |
// Merkle "proof" | |
MerkleTree.prototype.proof = function(val) { | |
const hash = sha256(''+val); | |
// find a leaf with matching hash | |
let idx = this.__hashes[0].indexOf(hash); | |
if (idx < 0) { return; } // value not present in tree | |
// construct proof | |
const proof = []; | |
for (let i = 0; i < this.__hashes.length - 1; i++) { | |
// choose hash to the left or right of element, depending on position | |
let offset = idx % 2 === 0 ? 1 : -1; | |
// if right pair is beyond the number of elements in array, pair with self | |
if (idx+offset >= this.__hashes[i].length) { offset = 0; } | |
if (offset >= 0) { proof.push('_'); } // empty slot before hash | |
proof.push(this.__hashes[i][idx+offset]); | |
if (offset < 0) { proof.push('_'); } // empty slot after hash | |
idx >>= 1; // integer division by 2 | |
} | |
return proof; | |
}; | |
// checkProof checks the validity of the supplied proof. It hashes the supplied | |
// value and recursively substitutes merkle hashes in slots provided in the | |
// proof. Returns the final value (for comparison with root) | |
function checkProof(val, proof) { | |
let hash = sha256(''+val); | |
if (!proof) { return hash; } | |
for (let i = 0; i < proof.length; i += 2) { | |
// read off two elements | |
const left = proof[i] === '_' ? hash : proof[i]; | |
const right = proof[i+1] === '_' ? hash : proof[i+1]; | |
hash = sha256(left + right); | |
} | |
return hash; | |
} | |
// To Student: Try changing values | |
const vals = ['S', 'N', 3, 1, 9, '🐶']; | |
console.log(`Hashing values ${vals} into Merkle tree...\n`); | |
const tree = new MerkleTree(vals); | |
console.log(`Merkle root for all values is: ${tree.root()}\n`); | |
['🐶', '😼'].forEach(val => { | |
const proof = tree.proof(val); | |
console.log(`Does Merkle tree contain '${val}'? Proof: ${proof}`); | |
console.log(`Verifying proof... Should produce same root with '${val}'...`); | |
if (checkProof(val, proof) == tree.root()) { | |
console.log(`... And it matches!`); | |
} else { | |
console.log(`... But there's no match`); | |
} | |
console.log(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// npm install lrs // | |
// Run with command: node ring.js | |
var lrs = require("lrs"); | |
// 3 parties generate their public/private key pairs | |
var alice = lrs.gen(); | |
var bob = lrs.gen(); | |
var eve = lrs.gen(); | |
// The list of public key is known and distributed | |
var group = [alice, bob, eve].map((m) => m.publicKey); | |
// Alice signs a message in behalf of one of the 3 | |
var signed = lrs.sign(group, alice, "The body is buried on the backyard."); | |
// Anyone is able to verify *some* of them signed that message | |
console.log(lrs.verify(group, signed, "The body is buried on the backyard.")); | |
// If that same person signs another message... | |
var signed2 = lrs.sign(group, alice, "Just kidding, he is alive."); | |
// We are able to tell the signature came from the same person | |
console.log(lrs.link(signed, signed2)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment