Skip to content

Commit

Permalink
Merge pull request #416 from o1-labs/feature/flexible-circuit-values
Browse files Browse the repository at this point in the history
Flexible circuit values
  • Loading branch information
mitschabaude authored Sep 28, 2022
2 parents f5838dd + 467a39a commit f11008b
Show file tree
Hide file tree
Showing 39 changed files with 133,022 additions and 132,210 deletions.
18 changes: 14 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/o1-labs/snarkyjs/compare/ba688523...HEAD)

(no unreleased changes yet)
### Added

- `Struct`, a new primitive for declaring composite, SNARK-compatible types https://github.com/o1-labs/snarkyjs/pull/416
- With this, we also added a way to include auxiliary, non-field element data in composite types
- Added `VerificationKey`, which is a `Struct` with auxiliary data, to pass verification keys to a `@method`
- BREAKING CHANGE: Change names related to circuit types: `AsFieldsAndAux<T>` -> `Provable<T>`, `AsFieldElement<T>` -> `ProvablePure<T>`, `circuitValue` -> `provable`
- BREAKING CHANGE: Change all `ofFields` and `ofBits` methods on circuit types to `fromFields` and `fromBits`

### Deprecated

- `CircuitValue` deprecated in favor of `Struct` https://github.com/o1-labs/snarkyjs/pull/416

## [0.6.0](https://github.com/o1-labs/snarkyjs/compare/f2ad423...ba688523)

Expand All @@ -29,10 +39,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Breaking change:** Rename the `Party` class to `AccountUpdate`. Also, rename other occurrences of "party" to "account update". https://github.com/o1-labs/snarkyjs/pull/393
- **Breaking change:** Don't require the account address as input to `SmartContract.compile()`, `SmartContract.digest()` and `SmartContract.analyzeMethods()` https://github.com/o1-labs/snarkyjs/pull/406
- BREAKING CHANGE: Rename the `Party` class to `AccountUpdate`. Also, rename other occurrences of "party" to "account update". https://github.com/o1-labs/snarkyjs/pull/393
- BREAKING CHANGE: Don't require the account address as input to `SmartContract.compile()`, `SmartContract.digest()` and `SmartContract.analyzeMethods()` https://github.com/o1-labs/snarkyjs/pull/406
- This works because the address / public key is now a variable in the method circuit; it used to be a constant
- **Breaking change:** Move `ZkProgram` to `Experimental.ZkProgram`
- BREAKING CHANGE: Move `ZkProgram` to `Experimental.ZkProgram`

## [0.5.4](https://github.com/o1-labs/snarkyjs/compare/3461333...f2ad423)

Expand Down
2 changes: 1 addition & 1 deletion MINA_COMMIT
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
The mina commit used to generate the backends for node and chrome is
778f499316fe439a7a843f91cd3c6e05484b3f7d
b54e58718a2d2cf1031eae0c63532be35b17550d
2 changes: 1 addition & 1 deletion run-unit-tests.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
npm run build:test
for f in ./dist/test/**/*.unit-test.js; do
echo "Running $f"
node $f || (echo 'tests failed' && exit 1)
node $f || exit 1;
done
6 changes: 3 additions & 3 deletions src/build/jsLayoutToTypes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function writeTsContent(types, isJson) {
mergeObject(converters, inner.converters);
output += `type ${Type} = ${inner.output};\n\n`;
if (!isJson) {
output += `let ${Type} = asFieldsAndAux<${Type}, Json.${Type}>(jsLayout.${Type} as any, customTypes);\n\n`;
output += `let ${Type} = provableFromLayout<${Type}, Json.${Type}>(jsLayout.${Type} as any, customTypes);\n\n`;
}
}

Expand All @@ -136,7 +136,7 @@ function writeTsContent(types, isJson) {
import { ${[...imports].join(', ')} } from '${importPath}';
${
!isJson
? "import { asFieldsAndAux, AsFieldsAndAux } from '../transaction-helpers.js';\n" +
? "import { provableFromLayout, ProvableExtended } from '../transaction-helpers.js';\n" +
"import * as Json from './transaction-json.js';\n" +
"import { jsLayout } from './js-layout.js';\n"
: ''
Expand All @@ -153,7 +153,7 @@ ${
(!isJson || '') &&
`
type CustomTypes = { ${customTypes
.map((c) => `${c.typeName}: AsFieldsAndAux<${c.type}, ${c.jsonType}>;`)
.map((c) => `${c.typeName}: ProvableExtended<${c.type}, ${c.jsonType}>;`)
.join(' ')} }
let customTypes: CustomTypes = { ${customTypeNames.join(', ')} };
`
Expand Down
Binary file modified src/chrome_bindings/plonk_wasm_bg.wasm
Binary file not shown.
320 changes: 160 additions & 160 deletions src/chrome_bindings/snarky_js_chrome.bc.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/examples/ex01_small_preimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Main extends Circuit {

const kp = Main.generateKeypair();

const preimage = Field.ofBits(Field.random().toBits().slice(0, 32));
const preimage = Field.fromBits(Field.random().toBits().slice(0, 32));
const hash = Poseidon.hash([preimage]);
const pi = Main.prove([preimage], [hash], kp);
console.log('proof', pi);
6 changes: 3 additions & 3 deletions src/examples/matrix_mul.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Field, circuitValue, Circuit } from 'snarkyjs';
import { Field, provable, Circuit } from 'snarkyjs';

// there are two ways of specifying an n*m matrix

// circuitValue
let Matrix3x3 = circuitValue<Field[][]>([
// provable
let Matrix3x3 = provable([
[Field, Field, Field],
[Field, Field, Field],
[Field, Field, Field],
Expand Down
16 changes: 6 additions & 10 deletions src/examples/party-witness.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
Types,
AccountUpdate,
PrivateKey,
Circuit,
circuitValue,
} from 'snarkyjs';
import { Types, AccountUpdate, PrivateKey, Circuit, provable } from 'snarkyjs';

let address = PrivateKey.random().toPublicKey();

Expand All @@ -23,7 +17,7 @@ let json = Types.AccountUpdate.toJSON(accountUpdateRaw);

if (address.toBase58() !== json.body.publicKey) throw Error('fail');

let Null = circuitValue<null>(null);
let Null = provable(null);

Circuit.runAndCheck(() => {
let accountUpdateWitness = AccountUpdate.witness(Null, () => ({
Expand All @@ -48,7 +42,9 @@ let result = Circuit.constraintSystem(() => {
Circuit.assertEqual(Types.AccountUpdate, accountUpdateWitness, accountUpdate);
});

console.log(`a accountUpdate has ${Types.AccountUpdate.sizeInFields()} fields`);
console.log(
`witnessing a accountUpdate and comparing it to another one creates ${result.rows} rows`
`an account update has ${Types.AccountUpdate.sizeInFields()} fields`
);
console.log(
`witnessing an account update and comparing it to another one creates ${result.rows} rows`
);
14 changes: 7 additions & 7 deletions src/examples/rollup/data_store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Circuit,
Bool,
AsFieldElements,
ProvablePure,
Field,
Poseidon,
asFieldElementsToConstant,
Expand Down Expand Up @@ -45,8 +45,8 @@ export interface KeyedDataStore<K, V, P> {

export class Keyed {
static InMemory<K, V>(
eltTyp: AsFieldElements<V>,
keyTyp: AsFieldElements<K>,
eltTyp: ProvablePure<V>,
keyTyp: ProvablePure<K>,
key: (v: V) => K,
depth: number
): KeyedDataStore<K, V, MerkleProof> {
Expand All @@ -66,7 +66,7 @@ export class Keyed {
for (var i = 0; i < n; ++i) {
xs.push(Field.zero);
}
return eltTyp.ofFields(xs);
return eltTyp.fromFields(xs);
})();

const getValue = (k: K): { value: V; empty: boolean } => {
Expand Down Expand Up @@ -132,14 +132,14 @@ export class Keyed {
}

export function IPFS<A>(
eltTyp: AsFieldElements<A>,
eltTyp: ProvablePure<A>,
ipfsRoot: string
): DataStore<A, MerkleProof> {
throw 'ipfs';
}

export function InMemory<A>(
eltTyp: AsFieldElements<A>,
eltTyp: ProvablePure<A>,
depth: number
): DataStore<A, MerkleProof> {
const P = MerkleProofFactory(depth);
Expand Down Expand Up @@ -195,7 +195,7 @@ export function InMemory<A>(
}

export function OnDisk<A>(
eltTyp: AsFieldElements<A>,
eltTyp: ProvablePure<A>,
path: string
): DataStore<A, MerkleProof> {
throw 'ondisk';
Expand Down
16 changes: 8 additions & 8 deletions src/examples/rollup/merkle_proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Field,
Circuit,
Poseidon,
AsFieldElements,
ProvablePure,
Optional,
} from 'snarkyjs';
import { DataStore, KeyedDataStore } from './data_store';
Expand Down Expand Up @@ -56,7 +56,7 @@ export function MerkleAccumulatorFactory<A extends CircuitValue>(
return [x.root];
}

static ofFields(xs: Field[]): MerkleAccumulator {
static fromFields(xs: Field[]): MerkleAccumulator {
return new MerkleAccumulator(xs[0]);
}

Expand Down Expand Up @@ -168,7 +168,7 @@ export function KeyedAccumulatorFactory<
return [x.root];
}

static ofFields(xs: Field[]): KeyedAccumulator {
static fromFields(xs: Field[]): KeyedAccumulator {
return new KeyedAccumulator(xs[0]);
}

Expand Down Expand Up @@ -258,10 +258,10 @@ export function MerkleProofFactory(depth: number) {
return x.path;
}

static ofFields(xs: Array<Field>): MerkleProof {
static fromFields(xs: Array<Field>): MerkleProof {
if (xs.length !== depth) {
throw new Error(
`MerkleTree: ofFields expected array of length ${depth}, got ${xs.length}`
`MerkleTree: fromFields expected array of length ${depth}, got ${xs.length}`
);
}
return new MerkleProof(xs);
Expand Down Expand Up @@ -290,7 +290,7 @@ export function IndexFactory(depth: number) {
return new Index(res);
}

static ofFields(xs: Field[]): Index {
static fromFields(xs: Field[]): Index {
return new Index(xs.map((x) => Bool.Unsafe.ofField(x)));
}

Expand Down Expand Up @@ -554,7 +554,7 @@ function constantIndex(xs: Array<Bool>): Array<boolean> {
}

export class Collection<A> {
eltTyp: AsFieldElements<A>;
eltTyp: ProvablePure<A>;
values:
| { computed: true; value: MerkleTree<A> }
| { computed: false; f: () => MerkleTree<A> };
Expand All @@ -572,7 +572,7 @@ export class Collection<A> {
return this.root;
}

constructor(eltTyp: AsFieldElements<A>, f: () => Tree<A>, root?: Field) {
constructor(eltTyp: ProvablePure<A>, f: () => Tree<A>, root?: Field) {
this.eltTyp = eltTyp;
this.cachedPaths = new Map();
this.cachedValues = new Map();
Expand Down
14 changes: 4 additions & 10 deletions src/examples/rollup/merkle_stack.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import {
AsFieldElements,
Circuit,
Field,
Poseidon,
CircuitValue,
} from 'snarkyjs';
import { ProvablePure, Circuit, Field, Poseidon, CircuitValue } from 'snarkyjs';

// TODO: Implement AsFieldElements
// TODO: Implement ProvablePure
export class MerkleStack<A extends CircuitValue> {
commitment: Field;
eltTyp: AsFieldElements<A>;
eltTyp: ProvablePure<A>;
values:
| { computed: true; value: Array<[A, Field]> }
| { computed: false; f: () => Array<[A, Field]> };
Expand All @@ -18,7 +12,7 @@ export class MerkleStack<A extends CircuitValue> {
return Poseidon.hash([comm].concat(x.toFields()));
}

constructor(eltTyp: AsFieldElements<A>, f: () => Array<[A, Field]>) {
constructor(eltTyp: ProvablePure<A>, f: () => Array<[A, Field]>) {
this.values = { computed: false, f };
this.eltTyp = eltTyp;
// TODO
Expand Down
14 changes: 7 additions & 7 deletions src/examples/zkapps/dex/dex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
Account,
Bool,
Circuit,
circuitValue,
provable,
CircuitValue,
DeployArgs,
Experimental,
Expand All @@ -19,6 +19,7 @@ import {
SmartContract,
Token,
UInt64,
VerificationKey,
} from 'snarkyjs';

export { Dex, DexTokenHolder, TokenContract, keys, addresses, tokenIds };
Expand Down Expand Up @@ -165,8 +166,8 @@ class Dex extends SmartContract {
}

// TODO: this is a pain -- let's define circuit values in one line, with a factory pattern
// we just have to make circuitValue return a class, that's it!
// class UInt64x2 extends circuitValue([UInt64, UInt64]) {}
// we just have to make provable return a class, that's it!
// class UInt64x2 extends provable([UInt64, UInt64]) {}
class UInt64x2 extends CircuitValue {
@prop 0: UInt64;
@prop 1: UInt64;
Expand Down Expand Up @@ -225,7 +226,7 @@ class DexTokenHolder extends SmartContract {

// TODO: getting the account update here w/o messing up the account updates structure is error-prone and non-obvious
let tokenYUpdate = AccountUpdate.witnessTree(
circuitValue<null>(null),
provable(null),
// need to walk two layers deeper, and need to respect the actual max number of child account updates
[[undefined, undefined, undefined], undefined, undefined],
() => {
Expand Down Expand Up @@ -321,7 +322,7 @@ class TokenContract extends SmartContract {

// this is a very standardized deploy method. instead, we could also take the account update from a callback
// => need callbacks for signatures
@method deployZkapp(address: PublicKey) {
@method deployZkapp(address: PublicKey, verificationKey: VerificationKey) {
let tokenId = this.experimental.token.id;
let zkapp = Experimental.createChildAccountUpdate(
this.self,
Expand All @@ -332,8 +333,7 @@ class TokenContract extends SmartContract {
...Permissions.default(),
send: Permissions.proof(),
});
// TODO pass in verification key --> make it a circuit value --> make circuit values able to hold auxiliary data
// AccountUpdate.setValue(zkapp.update.verificationKey, verificationKey);
AccountUpdate.setValue(zkapp.update.verificationKey, verificationKey);
zkapp.sign();
}

Expand Down
22 changes: 11 additions & 11 deletions src/examples/zkapps/dex/erc20.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
AsFieldElements,
ProvablePure,
Bool,
CircuitString,
circuitValue,
provablePure,
DeployArgs,
Field,
method,
Expand Down Expand Up @@ -38,12 +38,12 @@ type Erc20 = {

// events
events: {
Transfer: AsFieldElements<{
Transfer: ProvablePure<{
from: PublicKey;
to: PublicKey;
value: UInt64;
}>;
Approval: AsFieldElements<{
Approval: ProvablePure<{
owner: PublicKey;
spender: PublicKey;
value: UInt64;
Expand Down Expand Up @@ -151,16 +151,16 @@ class TrivialCoin extends SmartContract implements Erc20 {
}

events = {
Transfer: circuitValue<{ from: PublicKey; to: PublicKey; value: UInt64 }>({
Transfer: provablePure({
from: PublicKey,
to: PublicKey,
value: UInt64,
}),
Approval: circuitValue<{
owner: PublicKey;
spender: PublicKey;
value: UInt64;
}>({ owner: PublicKey, spender: PublicKey, value: UInt64 }),
Approval: provablePure({
owner: PublicKey,
spender: PublicKey,
value: UInt64,
}),
};

// additional API needed for zkApp token accounts
Expand Down Expand Up @@ -204,7 +204,7 @@ class TrivialCoin extends SmartContract implements Erc20 {
...Permissions.default(),
send: Permissions.proof(),
});
// TODO pass in verification key --> make it a circuit value --> make circuit values able to hold auxiliary data
// TODO pass in verification key
// AccountUpdate.setValue(zkapp.update.verificationKey, verificationKey);
zkapp.sign(zkappKey);
}
Expand Down
Loading

0 comments on commit f11008b

Please sign in to comment.