Skip to content

Instantly share code, notes, and snippets.

@liamzebedee
Created July 24, 2022 10:54
Show Gist options
  • Select an option

  • Save liamzebedee/53f2eba5b6a7ae4556da94b38f6b2de5 to your computer and use it in GitHub Desktop.

Select an option

Save liamzebedee/53f2eba5b6a7ae4556da94b38f6b2de5 to your computer and use it in GitHub Desktop.
import { SelfProof, Field, ZkProgram, verify, Poseidon, SmartContract, Scalar, arrayProp } from 'snarkyjs';
import {
CircuitValue,
prop,
Signature,
PrivateKey,
PublicKey,
} from 'snarkyjs';
//
// Helpers.
//
class Wallet {
constructor(
public pubKey: PublicKey,
public privKey: PrivateKey
) {
}
static createRandom() {
let privKey = PrivateKey.random();
let pubKey = PublicKey.fromPrivateKey(privKey);
return new Wallet(pubKey, privKey)
}
}
// This seems unnatural [1], but is actually a very natural consequence of how circuit definition works.
// See: https://github.com/o1-labs/snarkyjs/issues/224
// [1]: Contrasted with - return parseInt(field.toString())
function fieldToNumber(field: Field): number {
let i = 0
while (!field.equals(i)) {
i++
}
return i
}
//
// Circuit data types.
//
class Coin extends CircuitValue {
@prop amount: Field
@prop owner: PublicKey
constructor(amount: Field, owner: PublicKey) {
super();
this.amount = amount;
this.owner = owner;
}
static from(obj: any): Coin {
return new Coin(obj.amount, obj.owner)
}
}
class RawTransaction extends CircuitValue {
@prop inputIdx: Field;
@arrayProp(Coin, 5) outputs: Coin[];
constructor(input: Field, outputs: Coin[]) {
super();
this.inputIdx = input;
this.outputs = outputs;
}
sighash() {
return Poseidon.hash(this.toFields())
}
}
class Transaction extends CircuitValue {
@prop inputIdx: Field;
@prop sig: Signature;
@arrayProp(Coin, 5) outputs: Coin[];
constructor(input: Field, sig: Signature, outputs: Coin[]) {
super();
this.inputIdx = input;
this.sig = sig;
this.outputs = outputs;
}
sighash(): Field {
return (new RawTransaction(this.inputIdx, this.outputs)).sighash()
}
sign(privKey: PrivateKey) {
let msg = [this.sighash()]
let sig = Signature.create(privKey, msg);
this.sig = sig
}
// sigHash() {
// let data = [
// this.inputIdx,
// ...this.outputs.flatMap(output => ([ output.amount, ...output.owner.toFields() ]))
// ]
// return Poseidon.hash(data)
// }
}
//
// The ZK program.
//
let Minicoin = ZkProgram({
publicInput: Transaction,
methods: {
genesis: {
privateInputs: [],
method(tx: Transaction) {
// Genesis.
// (new Field(tx.outputs.length)).assertEquals(1)
tx.outputs[0].amount.assertEquals(new Field(1000))
}
},
transfer: {
privateInputs: [SelfProof],
method(t1: Transaction, t0: SelfProof<Transaction>) {
// Verify the sequence is correct.
// Verify the state at t=0 was computed correctly.
t0.verify();
// Verify the state at t=1.
// This is the core of the state machine.
// Perform transfer of the coin.
// Verify input coin.
// A1: select an output coin of the previous tx.
const prevNumOutputs = t0.publicInput.outputs.length
t1.inputIdx.assertLt(prevNumOutputs)
const uxto = t0.publicInput.outputs[fieldToNumber(t1.inputIdx)]
// A2: the transfer is from the owner of this uxto.
const hash = t1.sighash()
const msg = [hash];
t1.sig.verify(uxto.owner, msg)
// Verify output coins.
// A3: input == sum(outputs)
let sumOutputs = Field.zero
for (const output of t1.outputs) {
sumOutputs.add(output.amount)
}
uxto.amount.assertEquals(sumOutputs)
},
},
},
});
//
// Run.
//
let account1 = Wallet.createRandom()
let account2 = Wallet.createRandom()
const SIGNATURE_NULL = Signature.create(account1.privKey, [new Field(1)])
// const SIGNATURE_NULL = new Signature(Field.zero, new Scalar())
console.log('compiling Minicoin...');
const { verificationKey } = await Minicoin.compile();
let genesisTx = new Transaction(
Field.zero,
SIGNATURE_NULL,
[
Coin.from({
amount: new Field(1000),
owner: account1.pubKey
})
]
)
console.log(genesisTx.outputs.length)
console.log('Genesis...');
let genesis = await Minicoin.genesis(genesisTx)
process.exit(-1)
console.log('transfer #1...');
let input = genesis
let inputIdx = Field.zero
let outputs = [
{
amount: new Field(500),
owner: account1.pubKey,
},
{
amount: new Field(500),
owner: account2.pubKey,
}
].map(Coin.from)
process.exit(0)
let tx = new Transaction(inputIdx, SIGNATURE_NULL, outputs)
tx.sign(account1.privKey)
let proof = await Minicoin.transfer(tx, genesis);
proof.verify()
@liamzebedee

Copy link
Copy Markdown
Author
(base) ➜  snarkyjs git:(main) ✗ ./run src/examples/simple_quark.ts --keep
compiling Minicoin...
1
Genesis...
/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:3

....

Error: Expected array of length 1
    at raise_error (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4871008)
    at array_check_length (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4873899)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4879308
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39189)
    at Function.<anonymous> (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:73327)
    at Function.Class.<computed> [as ofFields] (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:601:52)
    at Function.ofFields (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:2710:32)
    at Object.ofFields (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:2794:32)
    at Function.ofFields (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:2710:32)
    at main (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:3862:26)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at v_ (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4906638)
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4034531
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at br (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3255867)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4034481
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at br (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3255867)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at B0 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4034364)
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39189)
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39207)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:622)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4072038
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at Pa (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3255403)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at jt (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4071984)
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at $a (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3253969)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3256548
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39189)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39442
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39136)
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:548)
    at U (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3247158)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3192257
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3196564
    at caml_call4 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:777)
    at La (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3196017)
    at z_ (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3196054)
    at H_ (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3196532)
    at caml_call6 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:963)
    at X_ (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3197165)
    at caml_call5 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:867)
    at zr (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3256568)
    at caml_call4 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:777)
    at K0 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4072083)
    at caml_call1 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:543)
    at time (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:3860151)
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39189)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39442
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39136)
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39207)
    at caml_call_gen (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2:39207)
    at caml_call3 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:702)
    at o0 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4072387)
    at caml_call2 (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:4:615)
    at r_ (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/node_bindings/snarky_js_node.bc.js:2215:4910254)
    at /Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:3755:89
    at withContextAsync (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:3475:20)
    at Object.prove [as genesis] (/Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/dist/server/index.js:3755:29)
    at file:///Users/liamz/Documents/Projects/shard/cairo/research/snarky/snarkyjs/src/examples/simple_quark.tmp.mjs:133:30
(base) ➜  snarkyjs git:(main) ✗ 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment