Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@
"jest": "^27.3.1",
"lint-staged": "^11.0.1",
"prettier": "^2.3.2",
"snarkyjs": "^0.11.3",
"ts-jest": "^27.0.7",
"typescript": "^4.7.2",
"snarkyjs": "0.10.*"
"typescript": "^4.7.2"
},
"dependencies": {
"snarkyjs-math": "^0.3.0",
"zod": "^3.21.4"
}
}
58 changes: 58 additions & 0 deletions src/Pepe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Field, SmartContract, state, State, method, Bool } from 'snarkyjs';
import { CircuitMath, CircuitNumber } from 'snarkyjs-math';
import { PepeStruct } from './generated/PepeStruct.js';

export class Pepe extends SmartContract {
@state(PepeStruct) pep = State<PepeStruct>();

init() {
super.init();

const p = new PepeStruct(
new Field(0),
new Field(0),
new Field(0)
);

this.pep.set(p)
}

@method test(): Bool {
const currentState: PepeStruct = this.pep.getAndAssertEquals();

return new Bool(true)
}

@method updateIssuer(issuer: Field) {
const pep: PepeStruct = this.pep.getAndAssertEquals();
pep.issuer = issuer
this.pep.set(pep)
}


@method updateExpiration(expiration: Field) {
const pep: PepeStruct = this.pep.getAndAssertEquals();
pep.expiration = expiration
this.pep.set(pep)
}

@method updateAccount(account: Field) {
const pep: PepeStruct = this.pep.getAndAssertEquals();
// pep.account = account
// this.pep.set(pep)
}



@method data(): [Field, Field, Field] {
const pep: PepeStruct = this.pep.getAndAssertEquals();

return [pep.issuer, pep.expiration, pep.account]
}

@method f(): Field {
const pep: PepeStruct = this.pep.getAndAssertEquals();

return pep._field0
}
}
162 changes: 162 additions & 0 deletions src/generated/PepeStruct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import {
Field,
SmartContract,
state,
State,
method,
Poseidon,
Bool,
Struct,
Circuit,
UInt64,
UInt32,
Provable,
} from 'snarkyjs';
import {
CircuitMath,
CircuitNumber,
} from 'snarkyjs-math/build/src/snarkyjs-math';

const ISSUER_OFFSET = new Field(1);
const ISSUER_MASK = new Field(2 ** 16);

const EXPIRATION_OFFSET = new Field(2 ** 16);
const EXPIRATION_MASK = new Field(2 ** 40);

// const ACCOUNT_OFFSET = new Field(2 ** 56);
// const ACCOUNT_MASK = new Field(2 ** 63);


export class PepeStruct extends Struct({
_field0: Field,
}) {
constructor(issuer: Field, expiration: Field, account: Field) {
super({
_field0: PepeStruct._initField0(issuer, expiration, account),
});

this.check();
}
public check() {}

get issuer(): Field {
// return this._get(this._field0, UInt64.from(ISSUER_OFFSET.toBigInt()), UInt64.from(ISSUER_MASK.toBigInt())
return this._get(this._field0, ISSUER_OFFSET, ISSUER_MASK);
// return new Field(1)
}

get expiration(): Field {
// return this._get(this._field0, UInt64.from(EXPIRATION_OFFSET.toBigInt()), UInt64.from(EXPIRATION_MASK.toBigInt())
return this._get(this._field0, EXPIRATION_OFFSET, EXPIRATION_MASK);
return new Field(2)
}

get account(): Field {
// return _get160(this._field0, ACCOUNT_OFFSET, ACCOUNT_MASK);
return new Field(3)
}

set issuer(value: Field) {
// this._field0 = this._set(this._field0, value, UInt64.from(ISSUER_OFFSET), UInt64.from(ISSUER_MASK))
this._field0 = this._set(this._field0, value, ISSUER_OFFSET, ISSUER_MASK);
}

set expiration(value: Field) {
this._field0 = this._set(this._field0, value, EXPIRATION_OFFSET, EXPIRATION_MASK);
}
// set account(value: Field) {
// this._field0 = _set160(this._field0, value, ACCOUNT_MASK, EXPIRATION_MASK);
// }

static _initField0(issuer: Field, expiration: Field, account: Field): Field {
const value = new Field(
issuer.mul(ISSUER_OFFSET).add(expiration.mul(EXPIRATION_OFFSET))
// r.add(account.mul(ACCOUNT_OFFSET))
);
return value;
}

private _get(currentValue: Field, offset: Field, size: Field): Field {
// console.log(currentValue.toString())
// console.log(`_get`)
const r = Provable.witness(Field, () => {
// const dirtyValue = UInt64.from(value).div(offset);
// return dirtyValue.mod(size).toFields()[0];


const dirtyValue = UInt64.from(currentValue).div(UInt64.from(offset));
// console.log(`dirty value: ${UInt64.fromcurrentValue.toBigInt()} / ${offset.toBigInt()} = ${dirtyValue.toBigInt()}`);
// q = 0xffdead / x10000 => 0xff
const q = dirtyValue.div(UInt64.from(size));
// console.log(`q: ${currentValue.toBigInt()} / ${size.toBigInt()} = ${q.toBigInt()}`);
// rest = 0xffdead % 0x10000 <=> r = 0xffdead - (q * 0x10000) => 0xdead
const p = q.mul(UInt64.from(size))
// console.log(`q * size: ${q.toBigInt()} * ${size.toBigInt()} = ${p.toBigInt()}`);
const value = dirtyValue.sub(p);
return value.toFields()[0]
// console.log(`value: ${dirtyValue.toBigInt()} - ${p.toBigInt()} = ${value.toBigInt()}`);
return dirtyValue.toFields()[0]
});

return r;
}
private _get160(
currentValue: Field,
offset: Field,
size: Field
): Field {
const r = Provable.witness(Field, () => {
// 0xffdeadff / 0x100 => 0xdead
const dirtyValue = currentValue.div(offset);
// q = 0xffdead / x10000 => 0xff
const q = dirtyValue.div(size);

// rest = 0xffdead % 0x10000 <=> r = 0xffdead - (q * 0x10000) => 0xdead
const rest = dirtyValue.sub(q.mul(size));
rest.assertLessThan(dirtyValue);
return rest;
// return dirtyValue.mod(size).toFields()[0];
});

return r;
}

// console.log(`setting new ${value.toBigInt()} in offset ${offset.toBigInt()}`)
private _set(
currentField: Field,
value: Field,
offset: Field,
size: Field
): Field {
// console.log(`_set`)

// const shiftedValue = new Field(UInt64.from(value).mul(offset).toBigInt())
const newField = Provable.witness(Field, () => {

const shiftedValue = value.mul(offset);
// console.log(`shifted: ${value.toBigInt()} * ${offset.toBigInt()} = ${shiftedValue.toBigInt()}`);
const currentValue = this._get(currentField, offset, size);
// console.log(`current: ${currentValue.toBigInt()}`);
// const newField = currentField.sub(currentValue).add(shiftedValue);
const newValue = currentField.sub(currentValue).add(shiftedValue);
// console.log(`new: ${newValue.toBigInt()}`);
return newValue;
})
return newField;
}

private _set160(
currentField: Field,
newValue: Field,
offset: Field,
size: Field
): Field {
// const shiftedValue = new Field(UInt64.from(value).mul(offset).toBigInt())
const shiftedValue = newValue.mul(offset);
const currentValue = this._get160(currentField, offset, size);
const newField = currentField.sub(currentValue).add(shiftedValue);
return newField;
}


}
156 changes: 156 additions & 0 deletions src/pepe.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import {
Field,
Mina,
PrivateKey,
PublicKey,
AccountUpdate,
Bool,
Circuit,
Provable,
fetchAccount,
} from 'snarkyjs';
import {
CircuitMath,
CircuitNumber,
} from 'snarkyjs-math/build/src/snarkyjs-math.js';
import { ZkappCommand } from 'snarkyjs/dist/node/lib/account_update.js';
import { PepeStruct } from './generated/PepeStruct.js';
import { Pepe } from './Pepe.js';

describe('pepe.js', () => {
let deployerAccount: PublicKey,
senderAccount: PublicKey,
zkAppPrivateKey: PrivateKey,
zkAppAddress: PublicKey,
deployerKey: PrivateKey,
senderKey: PrivateKey,
zkApp: Pepe;

beforeAll(async () => {
const useProof = false;

const Local = Mina.LocalBlockchain({ proofsEnabled: useProof });
Mina.setActiveInstance(Local);
// const { privateKey: deployerKey, publicKey: deployerAccount } = Local.testAccounts[0];
// const { privateKey: senderKey, publicKey: senderAccount } = Local.testAccounts[1];
deployerKey = Local.testAccounts[0].privateKey
deployerAccount = Local.testAccounts[0].publicKey
senderKey = Local.testAccounts[1].privateKey
senderAccount = Local.testAccounts[1].publicKey

// ----------------------------------------------------

// Create a public/private key pair. The public key is your address and where you deploy the zkApp to
zkAppPrivateKey = PrivateKey.random();
zkAppAddress = zkAppPrivateKey.toPublicKey();
zkApp = new Pepe(zkAppAddress);

console.log('compiling')
await Pepe.compile();

await fetchAccount({ publicKey: zkAppAddress });

zkApp = new Pepe(zkAppAddress);

const deployTxn = await Mina.transaction(deployerAccount, () => {
AccountUpdate.fundNewAccount(deployerAccount);
zkApp.deploy();
});
await deployTxn.sign([deployerKey, zkAppPrivateKey]).send();
});
beforeEach(async () => {


})

describe('updates field()', () => {
it('can set issuer', async () => {
const issuer = 0xf344

let updateTx = await Mina.transaction(senderAccount, () => {
// zkApp.updateField(new Field(packed));
zkApp.updateIssuer(new Field(issuer))
});

await updateTx.prove()
await updateTx.sign([senderKey]).send();

const pep = zkApp.pep.get()

expect(pep.issuer).toEqual(Field.from(issuer));

});
it('can set expiration', async () => {
const expiration = 0xffaabb

let updateTx = await Mina.transaction(senderAccount, () => {
// zkApp.updateField(new Field(packed));
zkApp.updateExpiration(new Field(expiration))
});

await updateTx.prove()
await updateTx.sign([senderKey]).send();

let pep = zkApp.pep.get()
expect(pep.expiration).toEqual(Field.from(expiration));
});

it('can update issuer', async () => {
const issuer1 = 0xf344

let updateTx = await Mina.transaction(senderAccount, () => {
zkApp.updateIssuer(new Field(issuer1))
});

await updateTx.prove()
await updateTx.sign([senderKey]).send();

expect(zkApp.pep.get().issuer).toEqual(Field.from(issuer1));

const issuer2 = 0xcaca
updateTx = await Mina.transaction(senderAccount, () => {
zkApp.updateIssuer(new Field(issuer2))
});

await updateTx.prove()
await updateTx.sign([senderKey]).send();
expect(zkApp.pep.get().issuer).toEqual(Field.from(issuer2));



})
it('can set all variables', async () => {

const issuer = 0xfeaa
const expiration = 0xffdead

let updateTx = await Mina.transaction(senderAccount, () => {
// zkApp.updateField(new Field(packed));
zkApp.updateIssuer(new Field(issuer))
// zkApp.updateExpiration(new Field(expiration))
});
await updateTx.prove()
await updateTx.sign([senderKey]).send();

let pep = zkApp.pep.get()
expect(pep.issuer).toEqual(Field.from(issuer));
updateTx = await Mina.transaction(senderAccount, () => {
// zkApp.updateField(new Field(packed));
zkApp.updateExpiration(new Field(expiration))
});
await updateTx.prove()
await updateTx.sign([senderKey]).send();

pep = zkApp.pep.get()
console.log(pep.issuer.toString(), pep.expiration.toString())

const expectedField = (expiration * (2 ** 16)) + issuer
expect(pep.expiration).toEqual(Field.from(expiration));
expect(pep._field0.toString()).toEqual(expectedField.toString())


})
it.skip('can set account', async () => {
});
});
});
Loading