o1js 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node/index.cjs +1082 -493
- package/dist/node/index.d.ts +3 -0
- package/dist/node/index.js +4 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/lib/mina/account-update.d.ts +149 -31
- package/dist/node/lib/mina/account-update.js +23 -1
- package/dist/node/lib/mina/account-update.js.map +1 -1
- package/dist/node/lib/mina/account.d.ts +1 -1
- package/dist/node/lib/mina/account.js +1 -1
- package/dist/node/lib/mina/account.js.map +1 -1
- package/dist/node/lib/mina/actions/offchain-state-rollup.d.ts +202 -31
- package/dist/node/lib/mina/actions/offchain-state-rollup.js +56 -74
- package/dist/node/lib/mina/actions/offchain-state-rollup.js.map +1 -1
- package/dist/node/lib/mina/actions/offchain-state-serialization.d.ts +4 -4
- package/dist/node/lib/mina/actions/offchain-state-serialization.js +10 -10
- package/dist/node/lib/mina/actions/offchain-state-serialization.js.map +1 -1
- package/dist/node/lib/mina/actions/offchain-state.d.ts +32 -1
- package/dist/node/lib/mina/actions/offchain-state.js +30 -20
- package/dist/node/lib/mina/actions/offchain-state.js.map +1 -1
- package/dist/node/lib/mina/fetch.js +4 -1
- package/dist/node/lib/mina/fetch.js.map +1 -1
- package/dist/node/lib/mina/graphql.d.ts +48 -47
- package/dist/node/lib/mina/graphql.js.map +1 -1
- package/dist/node/lib/mina/token/forest-iterator.d.ts +16 -4
- package/dist/node/lib/mina/zkapp.d.ts +10 -4
- package/dist/node/lib/provable/bytes.d.ts +8 -0
- package/dist/node/lib/provable/bytes.js.map +1 -1
- package/dist/node/lib/provable/core/provable-context.d.ts +2 -1
- package/dist/node/lib/provable/core/provable-context.js +12 -8
- package/dist/node/lib/provable/core/provable-context.js.map +1 -1
- package/dist/node/lib/provable/crypto/foreign-curve.d.ts +6 -0
- package/dist/node/lib/provable/crypto/foreign-curve.js.map +1 -1
- package/dist/node/lib/provable/crypto/foreign-ecdsa.d.ts +16 -2
- package/dist/node/lib/provable/crypto/foreign-ecdsa.js +20 -4
- package/dist/node/lib/provable/crypto/foreign-ecdsa.js.map +1 -1
- package/dist/node/lib/provable/field.d.ts +2 -2
- package/dist/node/lib/provable/field.js +2 -2
- package/dist/node/lib/provable/gadgets/elliptic-curve.d.ts +17 -2
- package/dist/node/lib/provable/gadgets/elliptic-curve.js +70 -40
- package/dist/node/lib/provable/gadgets/elliptic-curve.js.map +1 -1
- package/dist/node/lib/provable/int.d.ts +31 -4
- package/dist/node/lib/provable/int.js +70 -11
- package/dist/node/lib/provable/int.js.map +1 -1
- package/dist/node/lib/provable/merkle-tree-indexed.d.ts +615 -0
- package/dist/node/lib/provable/merkle-tree-indexed.js +614 -0
- package/dist/node/lib/provable/merkle-tree-indexed.js.map +1 -0
- package/dist/node/lib/provable/merkle-tree.d.ts +2 -2
- package/dist/node/lib/provable/merkle-tree.js +4 -3
- package/dist/node/lib/provable/merkle-tree.js.map +1 -1
- package/dist/node/lib/provable/option.d.ts +4 -1
- package/dist/node/lib/provable/option.js.map +1 -1
- package/dist/node/lib/provable/types/provable-derivers.d.ts +3 -3
- package/dist/node/lib/provable/types/unconstrained.d.ts +3 -3
- package/dist/node/lib/provable/types/unconstrained.js +2 -0
- package/dist/node/lib/provable/types/unconstrained.js.map +1 -1
- package/dist/node/lib/util/errors.d.ts +5 -1
- package/dist/node/lib/util/errors.js +9 -1
- package/dist/node/lib/util/errors.js.map +1 -1
- package/dist/web/index.d.ts +3 -0
- package/dist/web/index.js +65 -65
- package/dist/web/index.js.map +1 -1
- package/dist/web/lib/mina/account-update.d.ts +149 -31
- package/dist/web/lib/mina/account-update.js +23 -1
- package/dist/web/lib/mina/account-update.js.map +1 -1
- package/dist/web/lib/mina/account.d.ts +1 -1
- package/dist/web/lib/mina/account.js +1 -1
- package/dist/web/lib/mina/account.js.map +1 -1
- package/dist/web/lib/mina/actions/offchain-state-rollup.d.ts +202 -31
- package/dist/web/lib/mina/actions/offchain-state-rollup.js +56 -74
- package/dist/web/lib/mina/actions/offchain-state-rollup.js.map +1 -1
- package/dist/web/lib/mina/actions/offchain-state-serialization.d.ts +4 -4
- package/dist/web/lib/mina/actions/offchain-state-serialization.js +10 -10
- package/dist/web/lib/mina/actions/offchain-state-serialization.js.map +1 -1
- package/dist/web/lib/mina/actions/offchain-state.d.ts +32 -1
- package/dist/web/lib/mina/actions/offchain-state.js +30 -20
- package/dist/web/lib/mina/actions/offchain-state.js.map +1 -1
- package/dist/web/lib/mina/fetch.js +4 -1
- package/dist/web/lib/mina/fetch.js.map +1 -1
- package/dist/web/lib/mina/graphql.d.ts +48 -47
- package/dist/web/lib/mina/graphql.js.map +1 -1
- package/dist/web/lib/mina/token/forest-iterator.d.ts +16 -4
- package/dist/web/lib/mina/zkapp.d.ts +10 -4
- package/dist/web/lib/provable/bytes.d.ts +8 -0
- package/dist/web/lib/provable/bytes.js.map +1 -1
- package/dist/web/lib/provable/core/provable-context.d.ts +2 -1
- package/dist/web/lib/provable/core/provable-context.js +12 -8
- package/dist/web/lib/provable/core/provable-context.js.map +1 -1
- package/dist/web/lib/provable/crypto/foreign-curve.d.ts +6 -0
- package/dist/web/lib/provable/crypto/foreign-curve.js.map +1 -1
- package/dist/web/lib/provable/crypto/foreign-ecdsa.d.ts +16 -2
- package/dist/web/lib/provable/crypto/foreign-ecdsa.js +20 -4
- package/dist/web/lib/provable/crypto/foreign-ecdsa.js.map +1 -1
- package/dist/web/lib/provable/field.d.ts +2 -2
- package/dist/web/lib/provable/field.js +2 -2
- package/dist/web/lib/provable/gadgets/elliptic-curve.d.ts +17 -2
- package/dist/web/lib/provable/gadgets/elliptic-curve.js +70 -40
- package/dist/web/lib/provable/gadgets/elliptic-curve.js.map +1 -1
- package/dist/web/lib/provable/int.d.ts +31 -4
- package/dist/web/lib/provable/int.js +70 -11
- package/dist/web/lib/provable/int.js.map +1 -1
- package/dist/web/lib/provable/merkle-tree-indexed.d.ts +615 -0
- package/dist/web/lib/provable/merkle-tree-indexed.js +614 -0
- package/dist/web/lib/provable/merkle-tree-indexed.js.map +1 -0
- package/dist/web/lib/provable/merkle-tree.d.ts +2 -2
- package/dist/web/lib/provable/merkle-tree.js +4 -3
- package/dist/web/lib/provable/merkle-tree.js.map +1 -1
- package/dist/web/lib/provable/option.d.ts +4 -1
- package/dist/web/lib/provable/option.js.map +1 -1
- package/dist/web/lib/provable/types/provable-derivers.d.ts +3 -3
- package/dist/web/lib/provable/types/unconstrained.d.ts +3 -3
- package/dist/web/lib/provable/types/unconstrained.js +2 -0
- package/dist/web/lib/provable/types/unconstrained.js.map +1 -1
- package/dist/web/lib/util/errors.d.ts +5 -1
- package/dist/web/lib/util/errors.js +9 -1
- package/dist/web/lib/util/errors.js.map +1 -1
- package/package.json +1 -1
- package/src/examples/crypto/ecdsa/ecdsa.ts +2 -2
- package/src/examples/zkapps/voting/run-berkeley.ts +2 -2
- package/src/index.ts +9 -0
- package/src/lib/mina/account-update.ts +27 -2
- package/src/lib/mina/account.ts +1 -1
- package/src/lib/mina/actions/offchain-contract.unit-test.ts +9 -11
- package/src/lib/mina/actions/offchain-state-rollup.ts +71 -95
- package/src/lib/mina/actions/offchain-state-serialization.ts +19 -13
- package/src/lib/mina/actions/offchain-state.ts +75 -25
- package/src/lib/mina/fetch.ts +6 -3
- package/src/lib/mina/graphql.ts +41 -39
- package/src/lib/provable/bytes.ts +1 -0
- package/src/lib/provable/core/provable-context.ts +14 -7
- package/src/lib/provable/crypto/foreign-curve.ts +1 -0
- package/src/lib/provable/crypto/foreign-ecdsa.ts +31 -4
- package/src/lib/provable/field.ts +2 -2
- package/src/lib/provable/gadgets/elliptic-curve.ts +137 -48
- package/src/lib/provable/int.ts +85 -12
- package/src/lib/provable/merkle-tree-indexed.ts +795 -0
- package/src/lib/provable/merkle-tree.ts +4 -3
- package/src/lib/provable/option.ts +17 -13
- package/src/lib/provable/test/custom-gates-recursion.unit-test.ts +1 -1
- package/src/lib/provable/test/ecdsa.unit-test.ts +31 -2
- package/src/lib/provable/test/merkle-tree.unit-test.ts +280 -3
- package/src/lib/provable/types/provable-derivers.ts +3 -3
- package/src/lib/provable/types/unconstrained.ts +4 -3
- package/src/lib/testing/constraint-system.ts +6 -0
- package/src/lib/testing/equivalent.ts +6 -1
- package/src/lib/util/errors.ts +12 -0
package/dist/node/index.cjs
CHANGED
|
@@ -4584,13 +4584,7 @@ function constraintSystemToJS(cs) {
|
|
|
4584
4584
|
printGates(gates);
|
|
4585
4585
|
},
|
|
4586
4586
|
summary() {
|
|
4587
|
-
|
|
4588
|
-
gateTypes["Total rows"] = rows;
|
|
4589
|
-
for (let gate of gates) {
|
|
4590
|
-
gateTypes[gate.type] ??= 0;
|
|
4591
|
-
gateTypes[gate.type]++;
|
|
4592
|
-
}
|
|
4593
|
-
return gateTypes;
|
|
4587
|
+
return summarizeGates(gates);
|
|
4594
4588
|
}
|
|
4595
4589
|
};
|
|
4596
4590
|
}
|
|
@@ -4601,6 +4595,15 @@ function gatesFromJson(cs) {
|
|
|
4601
4595
|
});
|
|
4602
4596
|
return { publicInputSize: cs.public_input_size, gates };
|
|
4603
4597
|
}
|
|
4598
|
+
function summarizeGates(gates) {
|
|
4599
|
+
let gateTypes = {};
|
|
4600
|
+
gateTypes["Total rows"] = gates.length;
|
|
4601
|
+
for (let gate of gates) {
|
|
4602
|
+
gateTypes[gate.type] ??= 0;
|
|
4603
|
+
gateTypes[gate.type]++;
|
|
4604
|
+
}
|
|
4605
|
+
return gateTypes;
|
|
4606
|
+
}
|
|
4604
4607
|
function printGates(gates) {
|
|
4605
4608
|
for (let i = 0, n = gates.length; i < n; i++) {
|
|
4606
4609
|
let { type, wires, coeffs } = gates[i];
|
|
@@ -6131,6 +6134,8 @@ and Provable.asProver() blocks, which execute outside the proof.
|
|
|
6131
6134
|
* ```
|
|
6132
6135
|
*/
|
|
6133
6136
|
static from(value) {
|
|
6137
|
+
if (value instanceof _Unconstrained)
|
|
6138
|
+
return value;
|
|
6134
6139
|
return new _Unconstrained(true, value);
|
|
6135
6140
|
}
|
|
6136
6141
|
/**
|
|
@@ -7259,7 +7264,7 @@ var Field3 = class _Field {
|
|
|
7259
7264
|
* ```ts
|
|
7260
7265
|
* const someField = Field(42);
|
|
7261
7266
|
* const inverse = someField.inv();
|
|
7262
|
-
* inverse.assertEquals(Field(1).div(
|
|
7267
|
+
* inverse.assertEquals(Field(1).div(someField)); // This statement is always true regardless of the value of `someField`
|
|
7263
7268
|
* ```
|
|
7264
7269
|
*
|
|
7265
7270
|
* **Warning**: This is a modular inverse. See {@link div} method for more details.
|
|
@@ -7493,7 +7498,7 @@ var Field3 = class _Field {
|
|
|
7493
7498
|
* Assert that this {@link Field} is less than another "field-like" value.
|
|
7494
7499
|
*
|
|
7495
7500
|
* Note: This uses fewer constraints than `x.lessThan(y).assertTrue()`.
|
|
7496
|
-
* See {@link
|
|
7501
|
+
* See {@link lessThan} for more details.
|
|
7497
7502
|
*
|
|
7498
7503
|
* **Important**: If an assertion fails, the code throws an error.
|
|
7499
7504
|
*
|
|
@@ -11424,7 +11429,7 @@ var Sign3 = class _Sign extends CircuitValue {
|
|
|
11424
11429
|
return new _Sign(Field4(-1));
|
|
11425
11430
|
}
|
|
11426
11431
|
static check(x) {
|
|
11427
|
-
x.value.square().assertEquals(
|
|
11432
|
+
x.value.square().assertEquals(1);
|
|
11428
11433
|
}
|
|
11429
11434
|
static empty() {
|
|
11430
11435
|
return _Sign.one;
|
|
@@ -11449,7 +11454,10 @@ var Sign3 = class _Sign extends CircuitValue {
|
|
|
11449
11454
|
return new _Sign(this.value.mul(y.value));
|
|
11450
11455
|
}
|
|
11451
11456
|
isPositive() {
|
|
11452
|
-
return this.value.equals(
|
|
11457
|
+
return this.value.equals(1);
|
|
11458
|
+
}
|
|
11459
|
+
isNegative() {
|
|
11460
|
+
return this.value.equals(-1);
|
|
11453
11461
|
}
|
|
11454
11462
|
toString() {
|
|
11455
11463
|
return this.value.toString();
|
|
@@ -11502,9 +11510,9 @@ var Int64 = class _Int64 extends CircuitValue {
|
|
|
11502
11510
|
let isValidNegative = Field4.ORDER - xBigInt < TWO64;
|
|
11503
11511
|
if (!isValidPositive && !isValidNegative)
|
|
11504
11512
|
throw Error(`Int64: Expected a value between (-2^64, 2^64), got ${x}`);
|
|
11505
|
-
let magnitude =
|
|
11513
|
+
let magnitude = (isValidPositive ? x : x.neg()).toConstant();
|
|
11506
11514
|
let sign3 = isValidPositive ? Sign3.one : Sign3.minusOne;
|
|
11507
|
-
return new _Int64(
|
|
11515
|
+
return new _Int64(UInt642.Unsafe.fromField(magnitude), sign3);
|
|
11508
11516
|
}
|
|
11509
11517
|
// this doesn't check ranges because we assume they're already checked on UInts
|
|
11510
11518
|
/**
|
|
@@ -11578,13 +11586,20 @@ var Int64 = class _Int64 extends CircuitValue {
|
|
|
11578
11586
|
xInt.toField().assertEquals(x);
|
|
11579
11587
|
return xInt;
|
|
11580
11588
|
}
|
|
11589
|
+
/**
|
|
11590
|
+
* @deprecated Use {@link negV2()} instead.
|
|
11591
|
+
* The current implementation will not be backwards-compatible with v2.
|
|
11592
|
+
*/
|
|
11593
|
+
neg() {
|
|
11594
|
+
return new _Int64(this.magnitude, this.sgn.neg());
|
|
11595
|
+
}
|
|
11581
11596
|
/**
|
|
11582
11597
|
* Negates the value.
|
|
11583
11598
|
*
|
|
11584
11599
|
* `Int64.from(5).neg()` will turn into `Int64.from(-5)`
|
|
11585
11600
|
*/
|
|
11586
|
-
|
|
11587
|
-
return new _Int64(this.magnitude, this.sgn.neg());
|
|
11601
|
+
negV2() {
|
|
11602
|
+
return Provable.if(this.magnitude.value.equals(0), _Int64.zero, new _Int64(this.magnitude, this.sgn.neg()));
|
|
11588
11603
|
}
|
|
11589
11604
|
/**
|
|
11590
11605
|
* Addition with overflow checking.
|
|
@@ -11612,7 +11627,7 @@ var Int64 = class _Int64 extends CircuitValue {
|
|
|
11612
11627
|
*
|
|
11613
11628
|
* `x.div(y)` returns the floor of `x / y`, that is, the greatest
|
|
11614
11629
|
* `z` such that `z * y <= x`.
|
|
11615
|
-
*
|
|
11630
|
+
* On negative numbers, this rounds towards zero.
|
|
11616
11631
|
*/
|
|
11617
11632
|
div(y) {
|
|
11618
11633
|
let y_ = _Int64.from(y);
|
|
@@ -11620,16 +11635,28 @@ var Int64 = class _Int64 extends CircuitValue {
|
|
|
11620
11635
|
let sign3 = this.sgn.mul(y_.sgn);
|
|
11621
11636
|
return new _Int64(quotient, sign3);
|
|
11622
11637
|
}
|
|
11638
|
+
/**
|
|
11639
|
+
* @deprecated Use {@link modV2()} instead.
|
|
11640
|
+
* This implementation is vulnerable whenever `this` is zero.
|
|
11641
|
+
* It allows the prover to return `y` instead of 0 as the result.
|
|
11642
|
+
*/
|
|
11643
|
+
mod(y) {
|
|
11644
|
+
let y_ = UInt642.from(y);
|
|
11645
|
+
let rest = this.magnitude.divMod(y_).rest.value;
|
|
11646
|
+
rest = Provable.if(this.isPositive(), rest, y_.value.sub(rest));
|
|
11647
|
+
return new _Int64(new UInt642(rest.value));
|
|
11648
|
+
}
|
|
11623
11649
|
/**
|
|
11624
11650
|
* Integer remainder.
|
|
11625
11651
|
*
|
|
11626
11652
|
* `x.mod(y)` returns the value `z` such that `0 <= z < y` and
|
|
11627
11653
|
* `x - z` is divisible by `y`.
|
|
11628
11654
|
*/
|
|
11629
|
-
|
|
11655
|
+
modV2(y) {
|
|
11630
11656
|
let y_ = UInt642.from(y);
|
|
11631
11657
|
let rest = this.magnitude.divMod(y_).rest.value;
|
|
11632
|
-
|
|
11658
|
+
let isNonNegative = this.magnitude.equals(UInt642.zero).or(this.sgn.isPositive());
|
|
11659
|
+
rest = Provable.if(isNonNegative, rest, y_.value.sub(rest));
|
|
11633
11660
|
return new _Int64(new UInt642(rest.value));
|
|
11634
11661
|
}
|
|
11635
11662
|
/**
|
|
@@ -11647,11 +11674,40 @@ var Int64 = class _Int64 extends CircuitValue {
|
|
|
11647
11674
|
this.toField().assertEquals(y_.toField(), message);
|
|
11648
11675
|
}
|
|
11649
11676
|
/**
|
|
11650
|
-
*
|
|
11677
|
+
* @deprecated Use {@link isPositiveV2} instead.
|
|
11678
|
+
* The current implementation actually tests for non-negativity, but is wrong for the negative representation of 0.
|
|
11651
11679
|
*/
|
|
11652
11680
|
isPositive() {
|
|
11653
11681
|
return this.sgn.isPositive();
|
|
11654
11682
|
}
|
|
11683
|
+
/**
|
|
11684
|
+
* Checks if the value is positive (x > 0).
|
|
11685
|
+
*/
|
|
11686
|
+
isPositiveV2() {
|
|
11687
|
+
return this.magnitude.equals(UInt642.zero).not().and(this.sgn.isPositive());
|
|
11688
|
+
}
|
|
11689
|
+
// TODO add this when `checkV2` is enabled
|
|
11690
|
+
// then it will be the correct logic; right now it would be misleading
|
|
11691
|
+
/**
|
|
11692
|
+
* Checks if the value is non-negative (x >= 0).
|
|
11693
|
+
*/
|
|
11694
|
+
// isNonNegativeV2() {
|
|
11695
|
+
// return this.sgn.isPositive();
|
|
11696
|
+
// }
|
|
11697
|
+
// TODO add this when `checkV2` is enabled
|
|
11698
|
+
// then it will be the correct logic; right now it would be misleading
|
|
11699
|
+
/**
|
|
11700
|
+
* Checks if the value is negative (x < 0).
|
|
11701
|
+
*/
|
|
11702
|
+
// isNegative() {
|
|
11703
|
+
// return this.sgn.isNegative();
|
|
11704
|
+
// }
|
|
11705
|
+
// TODO enable this check method in v2, to force a unique representation of 0
|
|
11706
|
+
static checkV2({ magnitude, sgn }) {
|
|
11707
|
+
UInt642.check(magnitude);
|
|
11708
|
+
Sign3.check(sgn);
|
|
11709
|
+
magnitude.value.add(sgn.value).assertNotEquals(-1, "Int64: 0 must have positive sign");
|
|
11710
|
+
}
|
|
11655
11711
|
};
|
|
11656
11712
|
(0, import_tslib3.__decorate)([
|
|
11657
11713
|
prop,
|
|
@@ -14116,7 +14172,7 @@ function equals2(p1, p22, Curve) {
|
|
|
14116
14172
|
let yEquals = ForeignField.equals(p1.y, p22.y, Curve.modulus);
|
|
14117
14173
|
return xEquals.and(yEquals);
|
|
14118
14174
|
}
|
|
14119
|
-
function
|
|
14175
|
+
function verifyEcdsaGeneric(Curve, signature, msgHash, publicKey, multiScalarMul2, config = { G: { windowSize: 4 }, P: { windowSize: 4 } }) {
|
|
14120
14176
|
if (EcdsaSignature.isConstant(signature) && Field32.isConstant(msgHash) && Point.isConstant(publicKey)) {
|
|
14121
14177
|
let isValid = verifyEcdsaConstant(Curve, EcdsaSignature.toBigint(signature), Field32.toBigint(msgHash), Point.toBigint(publicKey));
|
|
14122
14178
|
return new Bool3(isValid);
|
|
@@ -14127,11 +14183,17 @@ function verifyEcdsa(Curve, signature, msgHash, publicKey, config = { G: { windo
|
|
|
14127
14183
|
let u1 = ForeignField.mul(msgHash, sInv, Curve.order);
|
|
14128
14184
|
let u2 = ForeignField.mul(r, sInv, Curve.order);
|
|
14129
14185
|
let G = Point.from(Curve.one);
|
|
14130
|
-
let R =
|
|
14186
|
+
let R = multiScalarMul2([u1, u2], [G, publicKey], Curve, config && [config.G, config.P], "assert-nonzero", config?.ia);
|
|
14131
14187
|
let Rx = ForeignField.mul(R.x, Field32.from(1n), Curve.order);
|
|
14132
14188
|
ForeignField.assertLessThan(Rx, Curve.order);
|
|
14133
14189
|
return Provable.equal(Field32.provable, Rx, r);
|
|
14134
14190
|
}
|
|
14191
|
+
function verifyEcdsa(Curve, signature, msgHash, publicKey, config = { G: { windowSize: 4 }, P: { windowSize: 4 } }) {
|
|
14192
|
+
return verifyEcdsaGeneric(Curve, signature, msgHash, publicKey, (scalars, points, Curve2, configs, mode, ia) => multiScalarMul(scalars, points, Curve2, configs, mode, ia, true), config);
|
|
14193
|
+
}
|
|
14194
|
+
function verifyEcdsaV2(Curve, signature, msgHash, publicKey, config = { G: { windowSize: 4 }, P: { windowSize: 3 } }) {
|
|
14195
|
+
return verifyEcdsaGeneric(Curve, signature, msgHash, publicKey, (scalars, points, Curve2, configs, mode, ia) => multiScalarMul(scalars, points, Curve2, configs, mode, ia, false), config);
|
|
14196
|
+
}
|
|
14135
14197
|
function verifyEcdsaConstant(Curve, { r, s }, msgHash, publicKey) {
|
|
14136
14198
|
let pk = Curve.from(publicKey);
|
|
14137
14199
|
if (Curve.equal(pk, Curve.zero))
|
|
@@ -14151,28 +14213,35 @@ function verifyEcdsaConstant(Curve, { r, s }, msgHash, publicKey) {
|
|
|
14151
14213
|
return false;
|
|
14152
14214
|
return Curve.Scalar.equal(R.x, r);
|
|
14153
14215
|
}
|
|
14154
|
-
function
|
|
14216
|
+
function multiScalarMulConstant(scalars, points, Curve, mode = "assert-nonzero") {
|
|
14155
14217
|
let n = points.length;
|
|
14156
14218
|
assert3(scalars.length === n, "Points and scalars lengths must match");
|
|
14157
14219
|
assertPositiveInteger(n, "Expected at least 1 point and scalar");
|
|
14158
14220
|
let useGlv = Curve.hasEndomorphism;
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
sum3 = Curve.add(sum3, Curve.scale(P[i], s[i]));
|
|
14168
|
-
}
|
|
14169
|
-
}
|
|
14170
|
-
if (mode === "assert-zero") {
|
|
14171
|
-
assert3(sum3.infinity, "scalar multiplication: expected zero result");
|
|
14172
|
-
return Point.from(Curve.zero);
|
|
14221
|
+
let s = scalars.map(Field32.toBigint);
|
|
14222
|
+
let P = points.map(Point.toBigint);
|
|
14223
|
+
let sum2 = Curve.zero;
|
|
14224
|
+
for (let i = 0; i < n; i++) {
|
|
14225
|
+
if (useGlv) {
|
|
14226
|
+
sum2 = Curve.add(sum2, Curve.Endo.scale(P[i], s[i]));
|
|
14227
|
+
} else {
|
|
14228
|
+
sum2 = Curve.add(sum2, Curve.scale(P[i], s[i]));
|
|
14173
14229
|
}
|
|
14174
|
-
|
|
14175
|
-
|
|
14230
|
+
}
|
|
14231
|
+
if (mode === "assert-zero") {
|
|
14232
|
+
assert3(sum2.infinity, "scalar multiplication: expected zero result");
|
|
14233
|
+
return Point.from(Curve.zero);
|
|
14234
|
+
}
|
|
14235
|
+
assert3(!sum2.infinity, "scalar multiplication: expected non-zero result");
|
|
14236
|
+
return Point.from(sum2);
|
|
14237
|
+
}
|
|
14238
|
+
function multiScalarMul(scalars, points, Curve, tableConfigs = [], mode = "assert-nonzero", ia, hashed = true) {
|
|
14239
|
+
let n = points.length;
|
|
14240
|
+
assert3(scalars.length === n, "Points and scalars lengths must match");
|
|
14241
|
+
assertPositiveInteger(n, "Expected at least 1 point and scalar");
|
|
14242
|
+
let useGlv = Curve.hasEndomorphism;
|
|
14243
|
+
if (scalars.every(Field32.isConstant) && points.every(Point.isConstant)) {
|
|
14244
|
+
return multiScalarMulConstant(scalars, points, Curve, mode);
|
|
14176
14245
|
}
|
|
14177
14246
|
let windowSizes = points.map((_, i) => tableConfigs[i]?.windowSize ?? 1);
|
|
14178
14247
|
let tables = points.map((P, i) => getPointTable(Curve, P, windowSizes[i], tableConfigs[i]?.multiples));
|
|
@@ -14212,15 +14281,23 @@ function multiScalarMul(scalars, points, Curve, tableConfigs = [], mode = "asser
|
|
|
14212
14281
|
}
|
|
14213
14282
|
let scalarChunks = scalars.map((s, i) => sliceField3(s, { maxBits, chunkSize: windowSizes[i] }));
|
|
14214
14283
|
const HashedPoint = Hashed.create(Point.provable);
|
|
14215
|
-
let hashedTables = tables.map((table) => table.map((point) => HashedPoint.hash(point)));
|
|
14216
14284
|
ia ??= initialAggregator(Curve);
|
|
14217
14285
|
let sum2 = Point.from(ia);
|
|
14286
|
+
let hashedTables = [];
|
|
14287
|
+
if (hashed) {
|
|
14288
|
+
hashedTables = tables.map((table) => table.map((point) => HashedPoint.hash(point)));
|
|
14289
|
+
}
|
|
14218
14290
|
for (let i = maxBits - 1; i >= 0; i--) {
|
|
14219
14291
|
for (let j = 0; j < n; j++) {
|
|
14220
14292
|
let windowSize = windowSizes[j];
|
|
14221
14293
|
if (i % windowSize === 0) {
|
|
14222
14294
|
let sj = scalarChunks[j][i / windowSize];
|
|
14223
|
-
let sjP
|
|
14295
|
+
let sjP;
|
|
14296
|
+
if (hashed) {
|
|
14297
|
+
sjP = windowSize === 1 ? points[j] : arrayGetGeneric(HashedPoint.provable, hashedTables[j], sj).unhash();
|
|
14298
|
+
} else {
|
|
14299
|
+
sjP = windowSize === 1 ? points[j] : arrayGetGeneric(Point.provable, tables[j], sj);
|
|
14300
|
+
}
|
|
14224
14301
|
let added = add2(sum2, sjP, Curve);
|
|
14225
14302
|
sum2 = Provable.if(sj.equals(0), Point.provable, sum2, added);
|
|
14226
14303
|
}
|
|
@@ -14389,6 +14466,7 @@ var EcdsaSignature = {
|
|
|
14389
14466
|
var Ecdsa = {
|
|
14390
14467
|
sign: signEcdsa,
|
|
14391
14468
|
verify: verifyEcdsa,
|
|
14469
|
+
verifyV2: verifyEcdsaV2,
|
|
14392
14470
|
Signature: EcdsaSignature
|
|
14393
14471
|
};
|
|
14394
14472
|
function reduceMrcStack(xs) {
|
|
@@ -14967,6 +15045,14 @@ var EcdsaSignature2 = class {
|
|
|
14967
15045
|
toBigInt() {
|
|
14968
15046
|
return { r: this.r.toBigInt(), s: this.s.toBigInt() };
|
|
14969
15047
|
}
|
|
15048
|
+
/**
|
|
15049
|
+
* @deprecated There is a security vulnerability in this method. Use {@link verifyV2} instead.
|
|
15050
|
+
*/
|
|
15051
|
+
verify(message, publicKey) {
|
|
15052
|
+
let msgHashBytes = Keccak.ethereum(message);
|
|
15053
|
+
let msgHash = keccakOutputToScalar(msgHashBytes, this.Constructor.Curve);
|
|
15054
|
+
return this.verifySignedHash(msgHash, publicKey);
|
|
15055
|
+
}
|
|
14970
15056
|
/**
|
|
14971
15057
|
* Verify the ECDSA signature given the message (an array of bytes) and public key (a {@link Curve} point).
|
|
14972
15058
|
*
|
|
@@ -15001,10 +15087,18 @@ var EcdsaSignature2 = class {
|
|
|
15001
15087
|
* isValid.assertTrue('signature verifies');
|
|
15002
15088
|
* ```
|
|
15003
15089
|
*/
|
|
15004
|
-
|
|
15090
|
+
verifyV2(message, publicKey) {
|
|
15005
15091
|
let msgHashBytes = Keccak.ethereum(message);
|
|
15006
15092
|
let msgHash = keccakOutputToScalar(msgHashBytes, this.Constructor.Curve);
|
|
15007
|
-
return this.
|
|
15093
|
+
return this.verifySignedHashV2(msgHash, publicKey);
|
|
15094
|
+
}
|
|
15095
|
+
/**
|
|
15096
|
+
* @deprecated There is a security vulnerability in this method. Use {@link verifySignedHashV2} instead.
|
|
15097
|
+
*/
|
|
15098
|
+
verifySignedHash(msgHash, publicKey) {
|
|
15099
|
+
let msgHash_ = this.Constructor.Curve.Scalar.from(msgHash);
|
|
15100
|
+
let publicKey_ = this.Constructor.Curve.from(publicKey);
|
|
15101
|
+
return Ecdsa.verify(this.Constructor.Curve.Bigint, toObject(this), msgHash_.value, toPoint(publicKey_));
|
|
15008
15102
|
}
|
|
15009
15103
|
/**
|
|
15010
15104
|
* Verify the ECDSA signature given the message hash (a {@link Scalar}) and public key (a {@link Curve} point).
|
|
@@ -15013,10 +15107,10 @@ var EcdsaSignature2 = class {
|
|
|
15013
15107
|
* In contrast, this method just takes the message hash (a curve scalar) as input, giving you flexibility in
|
|
15014
15108
|
* choosing the hashing algorithm.
|
|
15015
15109
|
*/
|
|
15016
|
-
|
|
15110
|
+
verifySignedHashV2(msgHash, publicKey) {
|
|
15017
15111
|
let msgHash_ = this.Constructor.Curve.Scalar.from(msgHash);
|
|
15018
15112
|
let publicKey_ = this.Constructor.Curve.from(publicKey);
|
|
15019
|
-
return Ecdsa.
|
|
15113
|
+
return Ecdsa.verifyV2(this.Constructor.Curve.Bigint, toObject(this), msgHash_.value, toPoint(publicKey_));
|
|
15020
15114
|
}
|
|
15021
15115
|
/**
|
|
15022
15116
|
* Create an {@link EcdsaSignature} by signing a message with a private key.
|
|
@@ -15878,7 +15972,7 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15878
15972
|
function emptyHashWithPrefix2(prefix) {
|
|
15879
15973
|
return salt2(prefix)[0];
|
|
15880
15974
|
}
|
|
15881
|
-
const
|
|
15975
|
+
const Events4 = {
|
|
15882
15976
|
empty() {
|
|
15883
15977
|
let hash3 = emptyHashWithPrefix2("MinaZkappEventsEmpty");
|
|
15884
15978
|
return { hash: hash3, data: [] };
|
|
@@ -15889,16 +15983,16 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15889
15983
|
return { hash: hash3, data: [event, ...events.data] };
|
|
15890
15984
|
},
|
|
15891
15985
|
fromList(events) {
|
|
15892
|
-
return [...events].reverse().reduce(
|
|
15986
|
+
return [...events].reverse().reduce(Events4.pushEvent, Events4.empty());
|
|
15893
15987
|
},
|
|
15894
15988
|
hash(events) {
|
|
15895
|
-
return
|
|
15989
|
+
return Events4.fromList(events).hash;
|
|
15896
15990
|
}
|
|
15897
15991
|
};
|
|
15898
15992
|
const EventsProvable = {
|
|
15899
|
-
...
|
|
15993
|
+
...Events4,
|
|
15900
15994
|
...dataAsHash({
|
|
15901
|
-
empty:
|
|
15995
|
+
empty: Events4.empty,
|
|
15902
15996
|
toValue(data) {
|
|
15903
15997
|
return data.map((row) => row.map((e) => Field5.toBigint(e)));
|
|
15904
15998
|
},
|
|
@@ -15910,13 +16004,13 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15910
16004
|
},
|
|
15911
16005
|
fromJSON(json) {
|
|
15912
16006
|
let data = json.map((row) => row.map((e) => Field5.fromJSON(e)));
|
|
15913
|
-
let hash3 =
|
|
16007
|
+
let hash3 = Events4.hash(data);
|
|
15914
16008
|
return { data, hash: hash3 };
|
|
15915
16009
|
},
|
|
15916
16010
|
Field: Field5
|
|
15917
16011
|
})
|
|
15918
16012
|
};
|
|
15919
|
-
const
|
|
16013
|
+
const Actions4 = {
|
|
15920
16014
|
// same as events but w/ different hash prefixes
|
|
15921
16015
|
empty() {
|
|
15922
16016
|
let hash3 = emptyHashWithPrefix2("MinaZkappActionsEmpty");
|
|
@@ -15931,7 +16025,7 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15931
16025
|
return { hash: hash3, data: [event, ...actions.data] };
|
|
15932
16026
|
},
|
|
15933
16027
|
fromList(events) {
|
|
15934
|
-
return [...events].reverse().reduce(
|
|
16028
|
+
return [...events].reverse().reduce(Actions4.pushEvent, Actions4.empty());
|
|
15935
16029
|
},
|
|
15936
16030
|
hash(events) {
|
|
15937
16031
|
return this.fromList(events).hash;
|
|
@@ -15948,9 +16042,9 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15948
16042
|
}
|
|
15949
16043
|
};
|
|
15950
16044
|
const ActionsProvable = {
|
|
15951
|
-
...
|
|
16045
|
+
...Actions4,
|
|
15952
16046
|
...dataAsHash({
|
|
15953
|
-
empty:
|
|
16047
|
+
empty: Actions4.empty,
|
|
15954
16048
|
toValue(data) {
|
|
15955
16049
|
return data.map((row) => row.map((e) => Field5.toBigint(e)));
|
|
15956
16050
|
},
|
|
@@ -15962,7 +16056,7 @@ function createEvents({ Field: Field5, Poseidon: Poseidon3 }) {
|
|
|
15962
16056
|
},
|
|
15963
16057
|
fromJSON(json) {
|
|
15964
16058
|
let data = json.map((row) => row.map((e) => Field5.fromJSON(e)));
|
|
15965
|
-
let hash3 =
|
|
16059
|
+
let hash3 = Actions4.hash(data);
|
|
15966
16060
|
return { data, hash: hash3 };
|
|
15967
16061
|
},
|
|
15968
16062
|
Field: Field5
|
|
@@ -18949,157 +19043,815 @@ function Option(type) {
|
|
|
18949
19043
|
};
|
|
18950
19044
|
}
|
|
18951
19045
|
|
|
18952
|
-
// dist/node/lib/
|
|
18953
|
-
var
|
|
18954
|
-
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
|
|
18963
|
-
|
|
18964
|
-
|
|
18965
|
-
|
|
18966
|
-
|
|
18967
|
-
getActions: () => getActions,
|
|
18968
|
-
getBalance: () => getBalance,
|
|
18969
|
-
getNetworkConstants: () => getNetworkConstants,
|
|
18970
|
-
getNetworkId: () => getNetworkId,
|
|
18971
|
-
getNetworkState: () => getNetworkState,
|
|
18972
|
-
getProofsEnabled: () => getProofsEnabled,
|
|
18973
|
-
hasAccount: () => hasAccount,
|
|
18974
|
-
sender: () => sender,
|
|
18975
|
-
setActiveInstance: () => setActiveInstance,
|
|
18976
|
-
transaction: () => transaction,
|
|
18977
|
-
waitForFunding: () => waitForFunding
|
|
18978
|
-
});
|
|
18979
|
-
|
|
18980
|
-
// dist/node/lib/mina/mina-instance.js
|
|
18981
|
-
var defaultAccountCreationFee = 1e9;
|
|
18982
|
-
var defaultNetworkConstants = {
|
|
18983
|
-
genesisTimestamp: UInt642.from(0),
|
|
18984
|
-
slotTime: UInt642.from(3 * 60 * 1e3),
|
|
18985
|
-
accountCreationFee: UInt642.from(defaultAccountCreationFee)
|
|
18986
|
-
};
|
|
18987
|
-
var ZkappStateLength = 8;
|
|
18988
|
-
var activeInstance = {
|
|
18989
|
-
getNetworkConstants: () => defaultNetworkConstants,
|
|
18990
|
-
currentSlot: noActiveInstance,
|
|
18991
|
-
hasAccount: noActiveInstance,
|
|
18992
|
-
getAccount: noActiveInstance,
|
|
18993
|
-
getNetworkState: noActiveInstance,
|
|
18994
|
-
sendTransaction: noActiveInstance,
|
|
18995
|
-
transaction: noActiveInstance,
|
|
18996
|
-
fetchEvents: noActiveInstance,
|
|
18997
|
-
fetchActions: noActiveInstance,
|
|
18998
|
-
getActions: noActiveInstance,
|
|
18999
|
-
proofsEnabled: true,
|
|
19000
|
-
getNetworkId: () => "testnet"
|
|
19001
|
-
};
|
|
19002
|
-
function setActiveInstance(m) {
|
|
19003
|
-
activeInstance = m;
|
|
19004
|
-
}
|
|
19005
|
-
function noActiveInstance() {
|
|
19006
|
-
throw Error("Must call Mina.setActiveInstance first");
|
|
19007
|
-
}
|
|
19008
|
-
function currentSlot() {
|
|
19009
|
-
return activeInstance.currentSlot();
|
|
19010
|
-
}
|
|
19011
|
-
function getAccount(publicKey, tokenId) {
|
|
19012
|
-
return activeInstance.getAccount(publicKey, tokenId);
|
|
19013
|
-
}
|
|
19014
|
-
function hasAccount(publicKey, tokenId) {
|
|
19015
|
-
return activeInstance.hasAccount(publicKey, tokenId);
|
|
19016
|
-
}
|
|
19017
|
-
function getNetworkId() {
|
|
19018
|
-
return activeInstance.getNetworkId();
|
|
19019
|
-
}
|
|
19020
|
-
function getNetworkConstants() {
|
|
19021
|
-
return activeInstance.getNetworkConstants();
|
|
19022
|
-
}
|
|
19023
|
-
function getNetworkState() {
|
|
19024
|
-
return activeInstance.getNetworkState();
|
|
19025
|
-
}
|
|
19026
|
-
function getBalance(publicKey, tokenId) {
|
|
19027
|
-
return activeInstance.getAccount(publicKey, tokenId).balance;
|
|
19028
|
-
}
|
|
19029
|
-
async function fetchEvents(publicKey, tokenId, filterOptions = {}) {
|
|
19030
|
-
return await activeInstance.fetchEvents(publicKey, tokenId, filterOptions);
|
|
19031
|
-
}
|
|
19032
|
-
async function fetchActions(publicKey, actionStates, tokenId) {
|
|
19033
|
-
return await activeInstance.fetchActions(publicKey, actionStates, tokenId);
|
|
19034
|
-
}
|
|
19035
|
-
function getActions(publicKey, actionStates, tokenId) {
|
|
19036
|
-
return activeInstance.getActions(publicKey, actionStates, tokenId);
|
|
19037
|
-
}
|
|
19038
|
-
function getProofsEnabled() {
|
|
19039
|
-
return activeInstance.proofsEnabled;
|
|
19040
|
-
}
|
|
19041
|
-
|
|
19042
|
-
// dist/node/lib/mina/precondition.js
|
|
19043
|
-
var NetworkPrecondition = {
|
|
19044
|
-
ignoreAll() {
|
|
19045
|
-
let stakingEpochData = {
|
|
19046
|
-
ledger: { hash: ignore(Field4(0)), totalCurrency: ignore(uint64()) },
|
|
19047
|
-
seed: ignore(Field4(0)),
|
|
19048
|
-
startCheckpoint: ignore(Field4(0)),
|
|
19049
|
-
lockCheckpoint: ignore(Field4(0)),
|
|
19050
|
-
epochLength: ignore(uint32())
|
|
19051
|
-
};
|
|
19052
|
-
let nextEpochData = cloneCircuitValue(stakingEpochData);
|
|
19053
|
-
return {
|
|
19054
|
-
snarkedLedgerHash: ignore(Field4(0)),
|
|
19055
|
-
blockchainLength: ignore(uint32()),
|
|
19056
|
-
minWindowDensity: ignore(uint32()),
|
|
19057
|
-
totalCurrency: ignore(uint64()),
|
|
19058
|
-
globalSlotSinceGenesis: ignore(uint32()),
|
|
19059
|
-
stakingEpochData,
|
|
19060
|
-
nextEpochData
|
|
19061
|
-
};
|
|
19046
|
+
// dist/node/lib/provable/merkle-tree.js
|
|
19047
|
+
var MerkleTree = class _MerkleTree {
|
|
19048
|
+
/**
|
|
19049
|
+
* Creates a new, empty [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
|
19050
|
+
* @param height The height of Merkle Tree.
|
|
19051
|
+
* @returns A new MerkleTree
|
|
19052
|
+
*/
|
|
19053
|
+
constructor(height) {
|
|
19054
|
+
this.height = height;
|
|
19055
|
+
this.nodes = {};
|
|
19056
|
+
this.zeroes = new Array(height);
|
|
19057
|
+
this.zeroes[0] = Field4(0);
|
|
19058
|
+
for (let i = 1; i < height; i += 1) {
|
|
19059
|
+
this.zeroes[i] = Poseidon2.hash([this.zeroes[i - 1], this.zeroes[i - 1]]);
|
|
19060
|
+
}
|
|
19062
19061
|
}
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
ignoreAll() {
|
|
19071
|
-
let appState = [];
|
|
19072
|
-
for (let i = 0; i < ZkappStateLength; ++i) {
|
|
19073
|
-
appState.push(ignore(Field4(0)));
|
|
19062
|
+
/**
|
|
19063
|
+
* Return a new MerkleTree with the same contents as this one.
|
|
19064
|
+
*/
|
|
19065
|
+
clone() {
|
|
19066
|
+
let newTree = new _MerkleTree(this.height);
|
|
19067
|
+
for (let [level, nodes] of Object.entries(this.nodes)) {
|
|
19068
|
+
newTree.nodes[level] = { ...nodes };
|
|
19074
19069
|
}
|
|
19075
|
-
return
|
|
19076
|
-
balance: ignore(uint64()),
|
|
19077
|
-
nonce: ignore(uint32()),
|
|
19078
|
-
receiptChainHash: ignore(Field4(0)),
|
|
19079
|
-
delegate: ignore(PublicKey2.empty()),
|
|
19080
|
-
state: appState,
|
|
19081
|
-
actionState: ignore(Actions.emptyActionState()),
|
|
19082
|
-
provedState: ignore(Bool4(false)),
|
|
19083
|
-
isNew: ignore(Bool4(false))
|
|
19084
|
-
};
|
|
19070
|
+
return newTree;
|
|
19085
19071
|
}
|
|
19086
|
-
|
|
19087
|
-
|
|
19088
|
-
|
|
19089
|
-
|
|
19072
|
+
/**
|
|
19073
|
+
* Returns a node which lives at a given index and level.
|
|
19074
|
+
* @param level Level of the node.
|
|
19075
|
+
* @param index Index of the node.
|
|
19076
|
+
* @returns The data of the node.
|
|
19077
|
+
*/
|
|
19078
|
+
getNode(level, index) {
|
|
19079
|
+
return this.nodes[level]?.[index.toString()] ?? this.zeroes[level];
|
|
19090
19080
|
}
|
|
19091
|
-
|
|
19092
|
-
|
|
19093
|
-
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
};
|
|
19081
|
+
/**
|
|
19082
|
+
* Returns a leaf at a given index.
|
|
19083
|
+
* @param index Index of the leaf.
|
|
19084
|
+
* @returns The data of the leaf.
|
|
19085
|
+
*/
|
|
19086
|
+
getLeaf(key) {
|
|
19087
|
+
return this.getNode(0, key);
|
|
19099
19088
|
}
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19089
|
+
/**
|
|
19090
|
+
* Returns the root of the [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
|
19091
|
+
* @returns The root of the Merkle Tree.
|
|
19092
|
+
*/
|
|
19093
|
+
getRoot() {
|
|
19094
|
+
return this.getNode(this.height - 1, 0n);
|
|
19095
|
+
}
|
|
19096
|
+
// TODO: this allows to set a node at an index larger than the size. OK?
|
|
19097
|
+
setNode(level, index, value) {
|
|
19098
|
+
(this.nodes[level] ??= {})[index.toString()] = value;
|
|
19099
|
+
}
|
|
19100
|
+
// TODO: if this is passed an index bigger than the max, it will set a couple of out-of-bounds nodes but not affect the real Merkle root. OK?
|
|
19101
|
+
/**
|
|
19102
|
+
* Sets the value of a leaf node at a given index to a given value.
|
|
19103
|
+
* @param index Position of the leaf node.
|
|
19104
|
+
* @param leaf New value.
|
|
19105
|
+
*/
|
|
19106
|
+
setLeaf(index, leaf) {
|
|
19107
|
+
if (index >= this.leafCount) {
|
|
19108
|
+
throw new Error(`index ${index} is out of range for ${this.leafCount} leaves.`);
|
|
19109
|
+
}
|
|
19110
|
+
this.setNode(0, index, leaf);
|
|
19111
|
+
let currIndex = index;
|
|
19112
|
+
for (let level = 1; level < this.height; level++) {
|
|
19113
|
+
currIndex /= 2n;
|
|
19114
|
+
const left = this.getNode(level - 1, currIndex * 2n);
|
|
19115
|
+
const right = this.getNode(level - 1, currIndex * 2n + 1n);
|
|
19116
|
+
this.setNode(level, currIndex, Poseidon2.hash([left, right]));
|
|
19117
|
+
}
|
|
19118
|
+
}
|
|
19119
|
+
/**
|
|
19120
|
+
* Returns the witness (also known as [Merkle Proof or Merkle Witness](https://computersciencewiki.org/index.php/Merkle_proof)) for the leaf at the given index.
|
|
19121
|
+
* @param index Position of the leaf node.
|
|
19122
|
+
* @returns The witness that belongs to the leaf.
|
|
19123
|
+
*/
|
|
19124
|
+
getWitness(index) {
|
|
19125
|
+
if (index >= this.leafCount) {
|
|
19126
|
+
throw new Error(`index ${index} is out of range for ${this.leafCount} leaves.`);
|
|
19127
|
+
}
|
|
19128
|
+
const witness2 = [];
|
|
19129
|
+
for (let level = 0; level < this.height - 1; level++) {
|
|
19130
|
+
const isLeft = index % 2n === 0n;
|
|
19131
|
+
const sibling = this.getNode(level, isLeft ? index + 1n : index - 1n);
|
|
19132
|
+
witness2.push({ isLeft, sibling });
|
|
19133
|
+
index /= 2n;
|
|
19134
|
+
}
|
|
19135
|
+
return witness2;
|
|
19136
|
+
}
|
|
19137
|
+
// TODO: this will always return true if the merkle tree was constructed normally; seems to be only useful for testing. remove?
|
|
19138
|
+
/**
|
|
19139
|
+
* Checks if the witness that belongs to the leaf at the given index is a valid witness.
|
|
19140
|
+
* @param index Position of the leaf node.
|
|
19141
|
+
* @returns True if the witness for the leaf node is valid.
|
|
19142
|
+
*/
|
|
19143
|
+
validate(index) {
|
|
19144
|
+
const path = this.getWitness(index);
|
|
19145
|
+
let hash3 = this.getNode(0, index);
|
|
19146
|
+
for (const node of path) {
|
|
19147
|
+
hash3 = Poseidon2.hash(node.isLeft ? [hash3, node.sibling] : [node.sibling, hash3]);
|
|
19148
|
+
}
|
|
19149
|
+
return hash3.toString() === this.getRoot().toString();
|
|
19150
|
+
}
|
|
19151
|
+
// TODO: should this take an optional offset? should it fail if the array is too long?
|
|
19152
|
+
/**
|
|
19153
|
+
* Fills all leaves of the tree.
|
|
19154
|
+
* @param leaves Values to fill the leaves with.
|
|
19155
|
+
*/
|
|
19156
|
+
fill(leaves) {
|
|
19157
|
+
leaves.forEach((value, index) => {
|
|
19158
|
+
this.setLeaf(BigInt(index), value);
|
|
19159
|
+
});
|
|
19160
|
+
}
|
|
19161
|
+
/**
|
|
19162
|
+
* Returns the amount of leaf nodes.
|
|
19163
|
+
* @returns Amount of leaf nodes.
|
|
19164
|
+
*/
|
|
19165
|
+
get leafCount() {
|
|
19166
|
+
return 2n ** BigInt(this.height - 1);
|
|
19167
|
+
}
|
|
19168
|
+
};
|
|
19169
|
+
var BaseMerkleWitness = class extends CircuitValue {
|
|
19170
|
+
height() {
|
|
19171
|
+
return this.constructor.height;
|
|
19172
|
+
}
|
|
19173
|
+
/**
|
|
19174
|
+
* Takes a {@link Witness} and turns it into a circuit-compatible Witness.
|
|
19175
|
+
* @param witness Witness.
|
|
19176
|
+
* @returns A circuit-compatible Witness.
|
|
19177
|
+
*/
|
|
19178
|
+
constructor(witness2) {
|
|
19179
|
+
super();
|
|
19180
|
+
let height = witness2.length + 1;
|
|
19181
|
+
if (height !== this.height()) {
|
|
19182
|
+
throw Error(`Length of witness ${height}-1 doesn't match static tree height ${this.height()}.`);
|
|
19183
|
+
}
|
|
19184
|
+
this.path = witness2.map((item) => item.sibling);
|
|
19185
|
+
this.isLeft = witness2.map((item) => Bool4(item.isLeft));
|
|
19186
|
+
}
|
|
19187
|
+
/**
|
|
19188
|
+
* Calculates a root depending on the leaf value.
|
|
19189
|
+
* @param leaf Value of the leaf node that belongs to this Witness.
|
|
19190
|
+
* @returns The calculated root.
|
|
19191
|
+
*/
|
|
19192
|
+
calculateRoot(leaf) {
|
|
19193
|
+
let hash3 = leaf;
|
|
19194
|
+
let n = this.height();
|
|
19195
|
+
for (let i = 1; i < n; ++i) {
|
|
19196
|
+
let isLeft = this.isLeft[i - 1];
|
|
19197
|
+
const [left, right] = conditionalSwap(isLeft, hash3, this.path[i - 1]);
|
|
19198
|
+
hash3 = Poseidon2.hash([left, right]);
|
|
19199
|
+
}
|
|
19200
|
+
return hash3;
|
|
19201
|
+
}
|
|
19202
|
+
/**
|
|
19203
|
+
* Calculates the index of the leaf node that belongs to this Witness.
|
|
19204
|
+
* @returns Index of the leaf.
|
|
19205
|
+
*/
|
|
19206
|
+
calculateIndex() {
|
|
19207
|
+
let powerOfTwo = Field4(1);
|
|
19208
|
+
let index = Field4(0);
|
|
19209
|
+
let n = this.height();
|
|
19210
|
+
for (let i = 1; i < n; ++i) {
|
|
19211
|
+
index = Provable.if(this.isLeft[i - 1], index, index.add(powerOfTwo));
|
|
19212
|
+
powerOfTwo = powerOfTwo.mul(2);
|
|
19213
|
+
}
|
|
19214
|
+
return index;
|
|
19215
|
+
}
|
|
19216
|
+
};
|
|
19217
|
+
function MerkleWitness(height) {
|
|
19218
|
+
class MerkleWitness_ extends BaseMerkleWitness {
|
|
19219
|
+
}
|
|
19220
|
+
MerkleWitness_.height = height;
|
|
19221
|
+
arrayProp(Field4, height - 1)(MerkleWitness_.prototype, "path");
|
|
19222
|
+
arrayProp(Bool4, height - 1)(MerkleWitness_.prototype, "isLeft");
|
|
19223
|
+
return MerkleWitness_;
|
|
19224
|
+
}
|
|
19225
|
+
function conditionalSwap(b2, x, y) {
|
|
19226
|
+
let m = b2.toField().mul(x.sub(y));
|
|
19227
|
+
const x_ = y.add(m);
|
|
19228
|
+
const y_ = x.sub(m);
|
|
19229
|
+
return [x_, y_];
|
|
19230
|
+
}
|
|
19231
|
+
|
|
19232
|
+
// dist/node/lib/provable/merkle-tree-indexed.js
|
|
19233
|
+
function IndexedMerkleMap(height) {
|
|
19234
|
+
var _a;
|
|
19235
|
+
assert3(height > 0, "height must be positive");
|
|
19236
|
+
assert3(height < 53, "height must be less than 53, so that we can use 64-bit floats to represent indices.");
|
|
19237
|
+
return _a = class IndexedMerkleMap extends IndexedMerkleMapBase {
|
|
19238
|
+
get height() {
|
|
19239
|
+
return height;
|
|
19240
|
+
}
|
|
19241
|
+
}, _a.provable = provableFromClass(_a, provableBase), _a;
|
|
19242
|
+
}
|
|
19243
|
+
var provableBase = {
|
|
19244
|
+
root: Field4,
|
|
19245
|
+
length: Field4,
|
|
19246
|
+
data: Unconstrained.provableWithEmpty({
|
|
19247
|
+
nodes: [],
|
|
19248
|
+
sortedLeaves: []
|
|
19249
|
+
})
|
|
19250
|
+
};
|
|
19251
|
+
var IndexedMerkleMapBase = class _IndexedMerkleMapBase {
|
|
19252
|
+
// static data defining constraints
|
|
19253
|
+
get height() {
|
|
19254
|
+
throw Error("Height must be defined in a subclass");
|
|
19255
|
+
}
|
|
19256
|
+
/**
|
|
19257
|
+
* Creates a new, empty Indexed Merkle Map.
|
|
19258
|
+
*/
|
|
19259
|
+
constructor() {
|
|
19260
|
+
let height = this.height;
|
|
19261
|
+
let nodes = Array(height);
|
|
19262
|
+
for (let level = 0; level < height; level++) {
|
|
19263
|
+
nodes[level] = [];
|
|
19264
|
+
}
|
|
19265
|
+
let firstLeaf = _IndexedMerkleMapBase._firstLeaf;
|
|
19266
|
+
let firstNode = Leaf.hashNode(firstLeaf).toBigInt();
|
|
19267
|
+
let root = Nodes.setLeaf(nodes, 0, firstNode);
|
|
19268
|
+
this.root = Field4(root);
|
|
19269
|
+
this.length = Field4(1);
|
|
19270
|
+
this.data = Unconstrained.from({ nodes, sortedLeaves: [firstLeaf] });
|
|
19271
|
+
}
|
|
19272
|
+
/**
|
|
19273
|
+
* Clone the entire Merkle map.
|
|
19274
|
+
*
|
|
19275
|
+
* This method is provable.
|
|
19276
|
+
*/
|
|
19277
|
+
clone() {
|
|
19278
|
+
let cloned = new this.constructor();
|
|
19279
|
+
cloned.root = this.root;
|
|
19280
|
+
cloned.length = this.length;
|
|
19281
|
+
cloned.data.updateAsProver(() => {
|
|
19282
|
+
let { nodes, sortedLeaves } = this.data.get();
|
|
19283
|
+
return {
|
|
19284
|
+
nodes: nodes.map((row) => [...row]),
|
|
19285
|
+
sortedLeaves: [...sortedLeaves]
|
|
19286
|
+
};
|
|
19287
|
+
});
|
|
19288
|
+
return cloned;
|
|
19289
|
+
}
|
|
19290
|
+
/**
|
|
19291
|
+
* Overwrite the entire Merkle map with another one.
|
|
19292
|
+
*
|
|
19293
|
+
* This method is provable.
|
|
19294
|
+
*/
|
|
19295
|
+
overwrite(other) {
|
|
19296
|
+
this.overwriteIf(true, other);
|
|
19297
|
+
}
|
|
19298
|
+
/**
|
|
19299
|
+
* Overwrite the entire Merkle map with another one, if the condition is true.
|
|
19300
|
+
*
|
|
19301
|
+
* This method is provable.
|
|
19302
|
+
*/
|
|
19303
|
+
overwriteIf(condition, other) {
|
|
19304
|
+
condition = Bool4(condition);
|
|
19305
|
+
this.root = Provable.if(condition, other.root, this.root);
|
|
19306
|
+
this.length = Provable.if(condition, other.length, this.length);
|
|
19307
|
+
this.data.updateAsProver(() => Bool4(condition).toBoolean() ? other.clone().data.get() : this.data.get());
|
|
19308
|
+
}
|
|
19309
|
+
/**
|
|
19310
|
+
* Insert a new leaf `(key, value)`.
|
|
19311
|
+
*
|
|
19312
|
+
* Proves that `key` doesn't exist yet.
|
|
19313
|
+
*/
|
|
19314
|
+
insert(key, value) {
|
|
19315
|
+
key = Field4(key);
|
|
19316
|
+
value = Field4(value);
|
|
19317
|
+
let index = this.length;
|
|
19318
|
+
let indexBits = index.toBits(this.height - 1);
|
|
19319
|
+
let low = Provable.witness(Leaf, () => this._findLeaf(key).low);
|
|
19320
|
+
let lowPath = this._proveInclusion(low, "Invalid low node (root)");
|
|
19321
|
+
assertStrictlyBetween(low.key, key, low.nextKey, "Key already exists in the tree");
|
|
19322
|
+
let newLow = { ...low, nextKey: key };
|
|
19323
|
+
this.root = this._proveUpdate(newLow, lowPath);
|
|
19324
|
+
this._setLeafUnconstrained(true, newLow);
|
|
19325
|
+
let leaf = Leaf.nextAfter(newLow, index, {
|
|
19326
|
+
key,
|
|
19327
|
+
value,
|
|
19328
|
+
nextKey: low.nextKey
|
|
19329
|
+
});
|
|
19330
|
+
let path = this._proveEmpty(indexBits);
|
|
19331
|
+
this.root = this._proveUpdate(leaf, path);
|
|
19332
|
+
this.length = this.length.add(1);
|
|
19333
|
+
this._setLeafUnconstrained(false, leaf);
|
|
19334
|
+
}
|
|
19335
|
+
/**
|
|
19336
|
+
* Update an existing leaf `(key, value)`.
|
|
19337
|
+
*
|
|
19338
|
+
* Proves that the `key` exists.
|
|
19339
|
+
*
|
|
19340
|
+
* Returns the previous value.
|
|
19341
|
+
*/
|
|
19342
|
+
update(key, value) {
|
|
19343
|
+
key = Field4(key);
|
|
19344
|
+
value = Field4(value);
|
|
19345
|
+
let self = Provable.witness(Leaf, () => this._findLeaf(key).self);
|
|
19346
|
+
let path = this._proveInclusion(self, "Key does not exist in the tree");
|
|
19347
|
+
self.key.assertEquals(key, "Invalid leaf (key)");
|
|
19348
|
+
let newSelf = { ...self, value };
|
|
19349
|
+
this.root = this._proveUpdate(newSelf, path);
|
|
19350
|
+
this._setLeafUnconstrained(true, newSelf);
|
|
19351
|
+
return self.value;
|
|
19352
|
+
}
|
|
19353
|
+
/**
|
|
19354
|
+
* Perform _either_ an insertion or update, depending on whether the key exists.
|
|
19355
|
+
*
|
|
19356
|
+
* Note: This method is handling both the `insert()` and `update()` case at the same time, so you
|
|
19357
|
+
* can use it if you don't know whether the key exists or not.
|
|
19358
|
+
*
|
|
19359
|
+
* However, this comes at an efficiency cost, so prefer to use `insert()` or `update()` if you know whether the key exists.
|
|
19360
|
+
*
|
|
19361
|
+
* Returns the previous value, as an option (which is `None` if the key didn't exist before).
|
|
19362
|
+
*/
|
|
19363
|
+
set(key, value) {
|
|
19364
|
+
key = Field4(key);
|
|
19365
|
+
value = Field4(value);
|
|
19366
|
+
let { low, self } = Provable.witness(LeafPair, () => this._findLeaf(key));
|
|
19367
|
+
let lowPath = this._proveInclusion(low, "Invalid low node (root)");
|
|
19368
|
+
assertBetween(low.key, key, low.nextKey, "Invalid low node (key)");
|
|
19369
|
+
let keyExists = low.nextKey.equals(key);
|
|
19370
|
+
let index = Provable.witness(Field4, () => self.index.get());
|
|
19371
|
+
index = Provable.if(keyExists, index, this.length);
|
|
19372
|
+
let indexBits = index.toBits(this.height - 1);
|
|
19373
|
+
let newLow = { ...low, nextKey: key };
|
|
19374
|
+
this.root = this._proveUpdate(newLow, lowPath);
|
|
19375
|
+
this._setLeafUnconstrained(true, newLow);
|
|
19376
|
+
let path = this._proveInclusionOrEmpty(keyExists, indexBits, self, "Invalid leaf (root)");
|
|
19377
|
+
assert3(keyExists.implies(self.key.equals(key)), "Invalid leaf (key)");
|
|
19378
|
+
let newLeaf = Leaf.nextAfter(newLow, index, {
|
|
19379
|
+
key,
|
|
19380
|
+
value,
|
|
19381
|
+
nextKey: Provable.if(keyExists, self.nextKey, low.nextKey)
|
|
19382
|
+
});
|
|
19383
|
+
this.root = this._proveUpdate(newLeaf, path);
|
|
19384
|
+
this.length = Provable.if(keyExists, this.length, this.length.add(1));
|
|
19385
|
+
this._setLeafUnconstrained(keyExists, newLeaf);
|
|
19386
|
+
return new OptionField({ isSome: keyExists, value: self.value });
|
|
19387
|
+
}
|
|
19388
|
+
/**
|
|
19389
|
+
* Get a value from a key.
|
|
19390
|
+
*
|
|
19391
|
+
* Proves that the key already exists in the map yet and fails otherwise.
|
|
19392
|
+
*/
|
|
19393
|
+
get(key) {
|
|
19394
|
+
key = Field4(key);
|
|
19395
|
+
let self = Provable.witness(Leaf, () => this._findLeaf(key).self);
|
|
19396
|
+
this._proveInclusion(self, "Key does not exist in the tree");
|
|
19397
|
+
self.key.assertEquals(key, "Invalid leaf (key)");
|
|
19398
|
+
return self.value;
|
|
19399
|
+
}
|
|
19400
|
+
/**
|
|
19401
|
+
* Get a value from a key.
|
|
19402
|
+
*
|
|
19403
|
+
* Returns an option which is `None` if the key doesn't exist. (In that case, the option's value is unconstrained.)
|
|
19404
|
+
*
|
|
19405
|
+
* Note that this is more flexible than `get()` and allows you to handle the case where the key doesn't exist.
|
|
19406
|
+
* However, it uses about twice as many constraints for that reason.
|
|
19407
|
+
*/
|
|
19408
|
+
getOption(key) {
|
|
19409
|
+
key = Field4(key);
|
|
19410
|
+
let { low, self } = Provable.witness(LeafPair, () => this._findLeaf(key));
|
|
19411
|
+
this._proveInclusion(low, "Invalid low node (root)");
|
|
19412
|
+
assertBetween(low.key, key, low.nextKey, "Invalid low node (key)");
|
|
19413
|
+
let keyExists = low.nextKey.equals(key);
|
|
19414
|
+
this._proveInclusionIf(keyExists, self, "Invalid leaf (root)");
|
|
19415
|
+
assert3(keyExists.implies(self.key.equals(key)), "Invalid leaf (key)");
|
|
19416
|
+
return new OptionField({ isSome: keyExists, value: self.value });
|
|
19417
|
+
}
|
|
19418
|
+
// methods to check for inclusion for a key without being concerned about the value
|
|
19419
|
+
/**
|
|
19420
|
+
* Prove that the given key exists in the map.
|
|
19421
|
+
*/
|
|
19422
|
+
assertIncluded(key, message) {
|
|
19423
|
+
key = Field4(key);
|
|
19424
|
+
let self = Provable.witness(Leaf, () => this._findLeaf(key).self);
|
|
19425
|
+
this._proveInclusion(self, message ?? "Key does not exist in the tree");
|
|
19426
|
+
self.key.assertEquals(key, "Invalid leaf (key)");
|
|
19427
|
+
}
|
|
19428
|
+
/**
|
|
19429
|
+
* Prove that the given key does not exist in the map.
|
|
19430
|
+
*/
|
|
19431
|
+
assertNotIncluded(key, message) {
|
|
19432
|
+
key = Field4(key);
|
|
19433
|
+
let low = Provable.witness(Leaf, () => this._findLeaf(key).low);
|
|
19434
|
+
this._proveInclusion(low, "Invalid low node (root)");
|
|
19435
|
+
assertStrictlyBetween(low.key, key, low.nextKey, message ?? "Key already exists in the tree");
|
|
19436
|
+
}
|
|
19437
|
+
/**
|
|
19438
|
+
* Check whether the given key exists in the map.
|
|
19439
|
+
*/
|
|
19440
|
+
isIncluded(key) {
|
|
19441
|
+
key = Field4(key);
|
|
19442
|
+
let low = Provable.witness(Leaf, () => this._findLeaf(key).low);
|
|
19443
|
+
this._proveInclusion(low, "Invalid low node (root)");
|
|
19444
|
+
assertBetween(low.key, key, low.nextKey, "Invalid low node (key)");
|
|
19445
|
+
return low.nextKey.equals(key);
|
|
19446
|
+
}
|
|
19447
|
+
// helper methods
|
|
19448
|
+
/**
|
|
19449
|
+
* Helper method to prove inclusion of a leaf in the tree.
|
|
19450
|
+
*/
|
|
19451
|
+
_proveInclusion(leaf, message) {
|
|
19452
|
+
let node = Leaf.hashNode(leaf);
|
|
19453
|
+
let { root, path } = this._computeRoot(node, leaf.index);
|
|
19454
|
+
root.assertEquals(this.root, message ?? "Leaf is not included in the tree");
|
|
19455
|
+
return path;
|
|
19456
|
+
}
|
|
19457
|
+
/**
|
|
19458
|
+
* Helper method to conditionally prove inclusion of a leaf in the tree.
|
|
19459
|
+
*/
|
|
19460
|
+
_proveInclusionIf(condition, leaf, message) {
|
|
19461
|
+
let node = Leaf.hashNode(leaf);
|
|
19462
|
+
let { root } = this._computeRoot(node, leaf.index);
|
|
19463
|
+
assert3(condition.implies(root.equals(this.root)), message ?? "Leaf is not included in the tree");
|
|
19464
|
+
}
|
|
19465
|
+
/**
|
|
19466
|
+
* Helper method to prove inclusion of an empty leaf in the tree.
|
|
19467
|
+
*
|
|
19468
|
+
* This validates the path against the current root, so that we can use it to insert a new leaf.
|
|
19469
|
+
*/
|
|
19470
|
+
_proveEmpty(index) {
|
|
19471
|
+
let node = Field4(0n);
|
|
19472
|
+
let { root, path } = this._computeRoot(node, index);
|
|
19473
|
+
root.assertEquals(this.root, "Leaf is not empty");
|
|
19474
|
+
return path;
|
|
19475
|
+
}
|
|
19476
|
+
/**
|
|
19477
|
+
* Helper method to conditionally prove inclusion of a leaf in the tree.
|
|
19478
|
+
*
|
|
19479
|
+
* If the condition is false, we prove that the tree contains an empty leaf instead.
|
|
19480
|
+
*/
|
|
19481
|
+
_proveInclusionOrEmpty(condition, index, leaf, message) {
|
|
19482
|
+
let node = Provable.if(condition, Leaf.hashNode(leaf), Field4(0n));
|
|
19483
|
+
let { root, path } = this._computeRoot(node, index);
|
|
19484
|
+
root.assertEquals(this.root, message ?? "Leaf is not included in the tree");
|
|
19485
|
+
return path;
|
|
19486
|
+
}
|
|
19487
|
+
/**
|
|
19488
|
+
* Helper method to update the root against a previously validated path.
|
|
19489
|
+
*
|
|
19490
|
+
* Returns the new root.
|
|
19491
|
+
*/
|
|
19492
|
+
_proveUpdate(leaf, path) {
|
|
19493
|
+
let node = Leaf.hashNode(leaf);
|
|
19494
|
+
let { root } = this._computeRoot(node, path.index, path.witness);
|
|
19495
|
+
return root;
|
|
19496
|
+
}
|
|
19497
|
+
/**
|
|
19498
|
+
* Helper method to compute the root given a leaf node and its index.
|
|
19499
|
+
*
|
|
19500
|
+
* The index can be given as a `Field` or as an array of bits.
|
|
19501
|
+
*/
|
|
19502
|
+
_computeRoot(node, index, witness2) {
|
|
19503
|
+
let indexBits = index instanceof Unconstrained ? Provable.witness(Provable.Array(Bool4, this.height - 1), () => Field4(index.get()).toBits(this.height - 1)) : index;
|
|
19504
|
+
let witness_ = witness2 ?? Provable.witnessFields(this.height - 1, () => {
|
|
19505
|
+
let witness3 = [];
|
|
19506
|
+
let index2 = Number(Field4.fromBits(indexBits));
|
|
19507
|
+
let { nodes } = this.data.get();
|
|
19508
|
+
for (let level = 0; level < this.height - 1; level++) {
|
|
19509
|
+
let i = index2 % 2 === 0 ? index2 + 1 : index2 - 1;
|
|
19510
|
+
let sibling = Nodes.getNode(nodes, level, i, false);
|
|
19511
|
+
witness3.push(sibling);
|
|
19512
|
+
index2 >>= 1;
|
|
19513
|
+
}
|
|
19514
|
+
return witness3;
|
|
19515
|
+
});
|
|
19516
|
+
assert3(indexBits.length === this.height - 1, "Invalid index size");
|
|
19517
|
+
assert3(witness_.length === this.height - 1, "Invalid witness size");
|
|
19518
|
+
for (let level = 0; level < this.height - 1; level++) {
|
|
19519
|
+
let isRight = indexBits[level];
|
|
19520
|
+
let sibling = witness_[level];
|
|
19521
|
+
let [right, left] = conditionalSwap(isRight, node, sibling);
|
|
19522
|
+
node = Poseidon2.hash([left, right]);
|
|
19523
|
+
}
|
|
19524
|
+
return { root: node, path: { witness: witness_, index: indexBits } };
|
|
19525
|
+
}
|
|
19526
|
+
/**
|
|
19527
|
+
* Given a key, returns both the low node and the leaf that contains the key.
|
|
19528
|
+
*
|
|
19529
|
+
* If the key does not exist, a dummy value is returned for the leaf.
|
|
19530
|
+
*
|
|
19531
|
+
* Can only be called outside provable code.
|
|
19532
|
+
*/
|
|
19533
|
+
_findLeaf(key_) {
|
|
19534
|
+
let key = typeof key_ === "bigint" ? key_ : key_.toBigInt();
|
|
19535
|
+
assert3(key >= 0n, "key must be positive");
|
|
19536
|
+
let leaves = this.data.get().sortedLeaves;
|
|
19537
|
+
if (key === 0n)
|
|
19538
|
+
return {
|
|
19539
|
+
low: Leaf.fromStored(leaves[leaves.length - 1], leaves.length - 1),
|
|
19540
|
+
self: Leaf.fromStored(leaves[0], 0)
|
|
19541
|
+
};
|
|
19542
|
+
let { lowIndex, foundValue } = bisectUnique(key, (i) => leaves[i].key, leaves.length);
|
|
19543
|
+
let iLow = foundValue ? lowIndex - 1 : lowIndex;
|
|
19544
|
+
let low = Leaf.fromStored(leaves[iLow], iLow);
|
|
19545
|
+
let iSelf = foundValue ? lowIndex : 0;
|
|
19546
|
+
let selfBase = foundValue ? leaves[lowIndex] : Leaf.toStored(Leaf.empty());
|
|
19547
|
+
let self = Leaf.fromStored(selfBase, iSelf);
|
|
19548
|
+
return { low, self };
|
|
19549
|
+
}
|
|
19550
|
+
/**
|
|
19551
|
+
* Update or append a leaf in our internal data structures
|
|
19552
|
+
*/
|
|
19553
|
+
_setLeafUnconstrained(leafExists, leaf) {
|
|
19554
|
+
Provable.asProver(() => {
|
|
19555
|
+
let { nodes, sortedLeaves } = this.data.get();
|
|
19556
|
+
let i = leaf.index.get();
|
|
19557
|
+
Nodes.setLeaf(nodes, i, Leaf.hashNode(leaf).toBigInt());
|
|
19558
|
+
let leafValue = Leaf.toStored(leaf);
|
|
19559
|
+
let iSorted = leaf.sortedIndex.get();
|
|
19560
|
+
if (Bool4(leafExists).toBoolean()) {
|
|
19561
|
+
sortedLeaves[iSorted % sortedLeaves.length] = leafValue;
|
|
19562
|
+
} else {
|
|
19563
|
+
sortedLeaves.splice(iSorted, 0, leafValue);
|
|
19564
|
+
}
|
|
19565
|
+
});
|
|
19566
|
+
}
|
|
19567
|
+
};
|
|
19568
|
+
IndexedMerkleMapBase.provable = void 0;
|
|
19569
|
+
IndexedMerkleMapBase._firstLeaf = {
|
|
19570
|
+
key: 0n,
|
|
19571
|
+
value: 0n,
|
|
19572
|
+
// the 0 key encodes the minimum and maximum at the same time
|
|
19573
|
+
// so, if a second node is inserted, it will get `nextKey = 0`, and thus point to the first node
|
|
19574
|
+
nextKey: 0n,
|
|
19575
|
+
index: 0
|
|
19576
|
+
};
|
|
19577
|
+
var Nodes;
|
|
19578
|
+
(function(Nodes2) {
|
|
19579
|
+
function setLeaf(nodes, index, leaf) {
|
|
19580
|
+
nodes[0][index] = leaf;
|
|
19581
|
+
let height = nodes.length;
|
|
19582
|
+
for (let level = 0; level < height - 1; level++) {
|
|
19583
|
+
let isLeft = index % 2 === 0;
|
|
19584
|
+
index = Math.floor(index / 2);
|
|
19585
|
+
let left = getNode(nodes, level, index * 2, isLeft);
|
|
19586
|
+
let right = getNode(nodes, level, index * 2 + 1, !isLeft);
|
|
19587
|
+
nodes[level + 1][index] = Poseidon.hash([left, right]);
|
|
19588
|
+
}
|
|
19589
|
+
return getNode(nodes, height - 1, 0, true);
|
|
19590
|
+
}
|
|
19591
|
+
Nodes2.setLeaf = setLeaf;
|
|
19592
|
+
function getNode(nodes, level, index, nonEmpty) {
|
|
19593
|
+
let node = nodes[level]?.[index];
|
|
19594
|
+
if (node === void 0) {
|
|
19595
|
+
if (nonEmpty)
|
|
19596
|
+
throw Error(`node at level=${level}, index=${index} was expected to be known, but isn't.`);
|
|
19597
|
+
node = empty4(level);
|
|
19598
|
+
}
|
|
19599
|
+
return node;
|
|
19600
|
+
}
|
|
19601
|
+
Nodes2.getNode = getNode;
|
|
19602
|
+
const emptyNodes = [0n];
|
|
19603
|
+
function empty4(level) {
|
|
19604
|
+
for (let i = emptyNodes.length; i <= level; i++) {
|
|
19605
|
+
let zero2 = emptyNodes[i - 1];
|
|
19606
|
+
emptyNodes[i] = Poseidon.hash([zero2, zero2]);
|
|
19607
|
+
}
|
|
19608
|
+
return emptyNodes[level];
|
|
19609
|
+
}
|
|
19610
|
+
Nodes2.empty = empty4;
|
|
19611
|
+
})(Nodes || (Nodes = {}));
|
|
19612
|
+
var BaseLeaf = class extends Struct({
|
|
19613
|
+
key: Field4,
|
|
19614
|
+
value: Field4,
|
|
19615
|
+
nextKey: Field4
|
|
19616
|
+
}) {
|
|
19617
|
+
};
|
|
19618
|
+
var Leaf = class extends Struct({
|
|
19619
|
+
value: Field4,
|
|
19620
|
+
key: Field4,
|
|
19621
|
+
nextKey: Field4,
|
|
19622
|
+
// auxiliary data that tells us where the leaf is stored
|
|
19623
|
+
index: Unconstrained.provableWithEmpty(0),
|
|
19624
|
+
sortedIndex: Unconstrained.provableWithEmpty(0)
|
|
19625
|
+
}) {
|
|
19626
|
+
/**
|
|
19627
|
+
* Compute a leaf node: the hash of a leaf that becomes part of the Merkle tree.
|
|
19628
|
+
*/
|
|
19629
|
+
static hashNode(leaf) {
|
|
19630
|
+
return Poseidon2.hashPacked(BaseLeaf, BaseLeaf.fromValue(leaf));
|
|
19631
|
+
}
|
|
19632
|
+
/**
|
|
19633
|
+
* Create a new leaf, given its low node and index.
|
|
19634
|
+
*/
|
|
19635
|
+
static nextAfter(low, index, leaf) {
|
|
19636
|
+
return {
|
|
19637
|
+
key: leaf.key,
|
|
19638
|
+
value: leaf.value,
|
|
19639
|
+
nextKey: leaf.nextKey,
|
|
19640
|
+
index: Unconstrained.witness(() => Number(index)),
|
|
19641
|
+
sortedIndex: Unconstrained.witness(() => low.sortedIndex.get() + 1)
|
|
19642
|
+
};
|
|
19643
|
+
}
|
|
19644
|
+
// convert to/from internally stored format
|
|
19645
|
+
static toStored(leaf) {
|
|
19646
|
+
return {
|
|
19647
|
+
key: leaf.key.toBigInt(),
|
|
19648
|
+
value: leaf.value.toBigInt(),
|
|
19649
|
+
nextKey: leaf.nextKey.toBigInt(),
|
|
19650
|
+
index: leaf.index.get()
|
|
19651
|
+
};
|
|
19652
|
+
}
|
|
19653
|
+
static fromStored(leaf, sortedIndex) {
|
|
19654
|
+
return {
|
|
19655
|
+
...leaf,
|
|
19656
|
+
index: Unconstrained.from(leaf.index),
|
|
19657
|
+
sortedIndex: Unconstrained.from(sortedIndex)
|
|
19658
|
+
};
|
|
19659
|
+
}
|
|
19660
|
+
};
|
|
19661
|
+
var LeafPair = class extends Struct({ low: Leaf, self: Leaf }) {
|
|
19662
|
+
};
|
|
19663
|
+
var OptionField = class extends Option(Field4) {
|
|
19664
|
+
};
|
|
19665
|
+
function bisectUnique(target, getValue, length) {
|
|
19666
|
+
let [iLow, iHigh] = [0, length - 1];
|
|
19667
|
+
if (getValue(iLow) > target)
|
|
19668
|
+
return { lowIndex: -1, foundValue: false };
|
|
19669
|
+
if (getValue(iHigh) < target)
|
|
19670
|
+
return { lowIndex: iHigh, foundValue: false };
|
|
19671
|
+
while (iHigh !== iLow) {
|
|
19672
|
+
let iMid = Math.ceil((iLow + iHigh) / 2);
|
|
19673
|
+
if (getValue(iMid) <= target) {
|
|
19674
|
+
iLow = iMid;
|
|
19675
|
+
} else {
|
|
19676
|
+
iHigh = iMid - 1;
|
|
19677
|
+
}
|
|
19678
|
+
}
|
|
19679
|
+
return { lowIndex: iLow, foundValue: getValue(iLow) === target };
|
|
19680
|
+
}
|
|
19681
|
+
function assertStrictlyBetween(low, x, high, message) {
|
|
19682
|
+
x.assertNotEquals(0n, message ?? "0 is not in any strict range");
|
|
19683
|
+
low.assertLessThan(x, message);
|
|
19684
|
+
let highIsZero = high.equals(0n);
|
|
19685
|
+
let xSafe = Provable.witness(Field4, () => highIsZero.toBoolean() ? 0n : x);
|
|
19686
|
+
let highSafe = Provable.witness(Field4, () => highIsZero.toBoolean() ? 1n : high);
|
|
19687
|
+
xSafe.assertLessThan(highSafe, message);
|
|
19688
|
+
assert3(xSafe.equals(x).or(highIsZero), message);
|
|
19689
|
+
assert3(highSafe.equals(high).or(highIsZero), message);
|
|
19690
|
+
}
|
|
19691
|
+
function assertBetween(low, x, high, message) {
|
|
19692
|
+
let xIsZero = x.equals(0n);
|
|
19693
|
+
let lowSafe = Provable.witness(Field4, () => xIsZero.toBoolean() ? 0n : low);
|
|
19694
|
+
let xSafe1 = Provable.witness(Field4, () => xIsZero.toBoolean() ? 1n : x);
|
|
19695
|
+
lowSafe.assertLessThan(xSafe1, message);
|
|
19696
|
+
assert3(lowSafe.equals(low).or(xIsZero), message);
|
|
19697
|
+
assert3(xSafe1.equals(x).or(xIsZero), message);
|
|
19698
|
+
let highIsZero = high.equals(0n);
|
|
19699
|
+
let xSafe0 = Provable.witness(Field4, () => highIsZero.toBoolean() ? 0n : x);
|
|
19700
|
+
xSafe0.assertLessThanOrEqual(high, message);
|
|
19701
|
+
assert3(xSafe0.equals(x).or(highIsZero), message);
|
|
19702
|
+
}
|
|
19703
|
+
|
|
19704
|
+
// dist/node/lib/mina/mina.js
|
|
19705
|
+
var mina_exports = {};
|
|
19706
|
+
__export(mina_exports, {
|
|
19707
|
+
LocalBlockchain: () => LocalBlockchain,
|
|
19708
|
+
Network: () => Network2,
|
|
19709
|
+
TestPublicKey: () => TestPublicKey,
|
|
19710
|
+
Transaction: () => Transaction,
|
|
19711
|
+
activeInstance: () => activeInstance,
|
|
19712
|
+
currentSlot: () => currentSlot,
|
|
19713
|
+
currentTransaction: () => currentTransaction,
|
|
19714
|
+
faucet: () => faucet,
|
|
19715
|
+
fetchActions: () => fetchActions,
|
|
19716
|
+
fetchEvents: () => fetchEvents,
|
|
19717
|
+
filterGroups: () => filterGroups,
|
|
19718
|
+
getAccount: () => getAccount,
|
|
19719
|
+
getActions: () => getActions,
|
|
19720
|
+
getBalance: () => getBalance,
|
|
19721
|
+
getNetworkConstants: () => getNetworkConstants,
|
|
19722
|
+
getNetworkId: () => getNetworkId,
|
|
19723
|
+
getNetworkState: () => getNetworkState,
|
|
19724
|
+
getProofsEnabled: () => getProofsEnabled,
|
|
19725
|
+
hasAccount: () => hasAccount,
|
|
19726
|
+
sender: () => sender,
|
|
19727
|
+
setActiveInstance: () => setActiveInstance,
|
|
19728
|
+
transaction: () => transaction,
|
|
19729
|
+
waitForFunding: () => waitForFunding
|
|
19730
|
+
});
|
|
19731
|
+
|
|
19732
|
+
// dist/node/lib/mina/mina-instance.js
|
|
19733
|
+
var defaultAccountCreationFee = 1e9;
|
|
19734
|
+
var defaultNetworkConstants = {
|
|
19735
|
+
genesisTimestamp: UInt642.from(0),
|
|
19736
|
+
slotTime: UInt642.from(3 * 60 * 1e3),
|
|
19737
|
+
accountCreationFee: UInt642.from(defaultAccountCreationFee)
|
|
19738
|
+
};
|
|
19739
|
+
var ZkappStateLength = 8;
|
|
19740
|
+
var activeInstance = {
|
|
19741
|
+
getNetworkConstants: () => defaultNetworkConstants,
|
|
19742
|
+
currentSlot: noActiveInstance,
|
|
19743
|
+
hasAccount: noActiveInstance,
|
|
19744
|
+
getAccount: noActiveInstance,
|
|
19745
|
+
getNetworkState: noActiveInstance,
|
|
19746
|
+
sendTransaction: noActiveInstance,
|
|
19747
|
+
transaction: noActiveInstance,
|
|
19748
|
+
fetchEvents: noActiveInstance,
|
|
19749
|
+
fetchActions: noActiveInstance,
|
|
19750
|
+
getActions: noActiveInstance,
|
|
19751
|
+
proofsEnabled: true,
|
|
19752
|
+
getNetworkId: () => "testnet"
|
|
19753
|
+
};
|
|
19754
|
+
function setActiveInstance(m) {
|
|
19755
|
+
activeInstance = m;
|
|
19756
|
+
}
|
|
19757
|
+
function noActiveInstance() {
|
|
19758
|
+
throw Error("Must call Mina.setActiveInstance first");
|
|
19759
|
+
}
|
|
19760
|
+
function currentSlot() {
|
|
19761
|
+
return activeInstance.currentSlot();
|
|
19762
|
+
}
|
|
19763
|
+
function getAccount(publicKey, tokenId) {
|
|
19764
|
+
return activeInstance.getAccount(publicKey, tokenId);
|
|
19765
|
+
}
|
|
19766
|
+
function hasAccount(publicKey, tokenId) {
|
|
19767
|
+
return activeInstance.hasAccount(publicKey, tokenId);
|
|
19768
|
+
}
|
|
19769
|
+
function getNetworkId() {
|
|
19770
|
+
return activeInstance.getNetworkId();
|
|
19771
|
+
}
|
|
19772
|
+
function getNetworkConstants() {
|
|
19773
|
+
return activeInstance.getNetworkConstants();
|
|
19774
|
+
}
|
|
19775
|
+
function getNetworkState() {
|
|
19776
|
+
return activeInstance.getNetworkState();
|
|
19777
|
+
}
|
|
19778
|
+
function getBalance(publicKey, tokenId) {
|
|
19779
|
+
return activeInstance.getAccount(publicKey, tokenId).balance;
|
|
19780
|
+
}
|
|
19781
|
+
async function fetchEvents(publicKey, tokenId, filterOptions = {}) {
|
|
19782
|
+
return await activeInstance.fetchEvents(publicKey, tokenId, filterOptions);
|
|
19783
|
+
}
|
|
19784
|
+
async function fetchActions(publicKey, actionStates, tokenId) {
|
|
19785
|
+
return await activeInstance.fetchActions(publicKey, actionStates, tokenId);
|
|
19786
|
+
}
|
|
19787
|
+
function getActions(publicKey, actionStates, tokenId) {
|
|
19788
|
+
return activeInstance.getActions(publicKey, actionStates, tokenId);
|
|
19789
|
+
}
|
|
19790
|
+
function getProofsEnabled() {
|
|
19791
|
+
return activeInstance.proofsEnabled;
|
|
19792
|
+
}
|
|
19793
|
+
|
|
19794
|
+
// dist/node/lib/mina/precondition.js
|
|
19795
|
+
var NetworkPrecondition = {
|
|
19796
|
+
ignoreAll() {
|
|
19797
|
+
let stakingEpochData = {
|
|
19798
|
+
ledger: { hash: ignore(Field4(0)), totalCurrency: ignore(uint64()) },
|
|
19799
|
+
seed: ignore(Field4(0)),
|
|
19800
|
+
startCheckpoint: ignore(Field4(0)),
|
|
19801
|
+
lockCheckpoint: ignore(Field4(0)),
|
|
19802
|
+
epochLength: ignore(uint32())
|
|
19803
|
+
};
|
|
19804
|
+
let nextEpochData = cloneCircuitValue(stakingEpochData);
|
|
19805
|
+
return {
|
|
19806
|
+
snarkedLedgerHash: ignore(Field4(0)),
|
|
19807
|
+
blockchainLength: ignore(uint32()),
|
|
19808
|
+
minWindowDensity: ignore(uint32()),
|
|
19809
|
+
totalCurrency: ignore(uint64()),
|
|
19810
|
+
globalSlotSinceGenesis: ignore(uint32()),
|
|
19811
|
+
stakingEpochData,
|
|
19812
|
+
nextEpochData
|
|
19813
|
+
};
|
|
19814
|
+
}
|
|
19815
|
+
};
|
|
19816
|
+
function ignore(dummy) {
|
|
19817
|
+
return { isSome: Bool4(false), value: dummy };
|
|
19818
|
+
}
|
|
19819
|
+
var uint32 = () => ({ lower: UInt322.from(0), upper: UInt322.MAXINT() });
|
|
19820
|
+
var uint64 = () => ({ lower: UInt642.from(0), upper: UInt642.MAXINT() });
|
|
19821
|
+
var AccountPrecondition = {
|
|
19822
|
+
ignoreAll() {
|
|
19823
|
+
let appState = [];
|
|
19824
|
+
for (let i = 0; i < ZkappStateLength; ++i) {
|
|
19825
|
+
appState.push(ignore(Field4(0)));
|
|
19826
|
+
}
|
|
19827
|
+
return {
|
|
19828
|
+
balance: ignore(uint64()),
|
|
19829
|
+
nonce: ignore(uint32()),
|
|
19830
|
+
receiptChainHash: ignore(Field4(0)),
|
|
19831
|
+
delegate: ignore(PublicKey2.empty()),
|
|
19832
|
+
state: appState,
|
|
19833
|
+
actionState: ignore(Actions.emptyActionState()),
|
|
19834
|
+
provedState: ignore(Bool4(false)),
|
|
19835
|
+
isNew: ignore(Bool4(false))
|
|
19836
|
+
};
|
|
19837
|
+
}
|
|
19838
|
+
};
|
|
19839
|
+
var GlobalSlotPrecondition = {
|
|
19840
|
+
ignoreAll() {
|
|
19841
|
+
return ignore(uint32());
|
|
19842
|
+
}
|
|
19843
|
+
};
|
|
19844
|
+
var Preconditions = {
|
|
19845
|
+
ignoreAll() {
|
|
19846
|
+
return {
|
|
19847
|
+
account: AccountPrecondition.ignoreAll(),
|
|
19848
|
+
network: NetworkPrecondition.ignoreAll(),
|
|
19849
|
+
validWhile: GlobalSlotPrecondition.ignoreAll()
|
|
19850
|
+
};
|
|
19851
|
+
}
|
|
19852
|
+
};
|
|
19853
|
+
function preconditions(accountUpdate, isSelf) {
|
|
19854
|
+
initializePreconditions(accountUpdate, isSelf);
|
|
19103
19855
|
return {
|
|
19104
19856
|
account: Account3(accountUpdate),
|
|
19105
19857
|
network: Network(accountUpdate),
|
|
@@ -19599,6 +20351,26 @@ var TransactionVersion3 = {
|
|
|
19599
20351
|
current: () => UInt322.from(protocolVersions.txnVersion)
|
|
19600
20352
|
};
|
|
19601
20353
|
var zkAppProver = Prover();
|
|
20354
|
+
var Events3 = {
|
|
20355
|
+
...Events,
|
|
20356
|
+
pushEvent(events, event) {
|
|
20357
|
+
events = Events.pushEvent(events, event);
|
|
20358
|
+
Provable.asProver(() => {
|
|
20359
|
+
events.data[0] = events.data[0].map((e) => Field4(Field4.toBigint(e)));
|
|
20360
|
+
});
|
|
20361
|
+
return events;
|
|
20362
|
+
}
|
|
20363
|
+
};
|
|
20364
|
+
var Actions3 = {
|
|
20365
|
+
...Actions,
|
|
20366
|
+
pushEvent(actions, action) {
|
|
20367
|
+
actions = Actions.pushEvent(actions, action);
|
|
20368
|
+
Provable.asProver(() => {
|
|
20369
|
+
actions.data[0] = actions.data[0].map((e) => Field4(Field4.toBigint(e)));
|
|
20370
|
+
});
|
|
20371
|
+
return actions;
|
|
20372
|
+
}
|
|
20373
|
+
};
|
|
19602
20374
|
var True = () => Bool4(true);
|
|
19603
20375
|
var False = () => Bool4(false);
|
|
19604
20376
|
var VerificationKeyPermission = class _VerificationKeyPermission {
|
|
@@ -20337,8 +21109,8 @@ var AccountUpdate3 = class _AccountUpdate {
|
|
|
20337
21109
|
return pretty;
|
|
20338
21110
|
}
|
|
20339
21111
|
};
|
|
20340
|
-
AccountUpdate3.Actions =
|
|
20341
|
-
AccountUpdate3.Events =
|
|
21112
|
+
AccountUpdate3.Actions = Actions3;
|
|
21113
|
+
AccountUpdate3.Events = Events3;
|
|
20342
21114
|
AccountUpdate3.signingInfo = provable({
|
|
20343
21115
|
isSameAsFeePayer: Bool4,
|
|
20344
21116
|
nonce: UInt322
|
|
@@ -20878,7 +21650,7 @@ function newAccount(accountId2) {
|
|
|
20878
21650
|
account.permissions = Permissions.initial();
|
|
20879
21651
|
return account;
|
|
20880
21652
|
}
|
|
20881
|
-
function parseFetchedAccount(
|
|
21653
|
+
function parseFetchedAccount(account) {
|
|
20882
21654
|
const { publicKey, nonce, zkappState, balance, permissions, timing: { cliffAmount, cliffTime, initialMinimumBalance, vestingIncrement, vestingPeriod }, delegateAccount, receiptChainHash, actionState, token, tokenSymbol, verificationKey, provedState, zkappUri } = account;
|
|
20883
21655
|
let hasZkapp = zkappState !== null || verificationKey !== null || actionState !== null || zkappUri !== null || provedState;
|
|
20884
21656
|
let partialAccount = {
|
|
@@ -21214,7 +21986,7 @@ async function fetchAccountInternal(accountInfo, graphqlEndpoint = networkConfig
|
|
|
21214
21986
|
let [response, error] = await makeGraphqlRequest(accountQuery(publicKey, tokenId ?? TokenId4.toBase58(TokenId4.default)), graphqlEndpoint, networkConfig.minaFallbackEndpoints, config);
|
|
21215
21987
|
if (error !== void 0)
|
|
21216
21988
|
return { account: void 0, error };
|
|
21217
|
-
let fetchedAccount = response?.data;
|
|
21989
|
+
let fetchedAccount = response?.data?.account;
|
|
21218
21990
|
if (!fetchedAccount) {
|
|
21219
21991
|
return {
|
|
21220
21992
|
account: void 0,
|
|
@@ -21239,8 +22011,11 @@ var accountsToFetch = {};
|
|
|
21239
22011
|
var networksToFetch = {};
|
|
21240
22012
|
var actionsToFetch = {};
|
|
21241
22013
|
var genesisConstantsCache = {};
|
|
22014
|
+
var emptyKey = PublicKey2.empty().toBase58();
|
|
21242
22015
|
function markAccountToBeFetched(publicKey, tokenId, graphqlEndpoint) {
|
|
21243
22016
|
let publicKeyBase58 = publicKey.toBase58();
|
|
22017
|
+
if (publicKeyBase58 === emptyKey)
|
|
22018
|
+
return;
|
|
21244
22019
|
let tokenBase58 = TokenId4.toBase58(tokenId);
|
|
21245
22020
|
accountsToFetch[`${publicKeyBase58};${tokenBase58};${graphqlEndpoint}`] = {
|
|
21246
22021
|
publicKey: publicKeyBase58,
|
|
@@ -21587,8 +22362,8 @@ var Lightnet;
|
|
|
21587
22362
|
Lightnet2.listAcquiredKeyPairs = listAcquiredKeyPairs;
|
|
21588
22363
|
})(Lightnet || (Lightnet = {}));
|
|
21589
22364
|
function updateActionState(actions, actionState) {
|
|
21590
|
-
let actionHash =
|
|
21591
|
-
return
|
|
22365
|
+
let actionHash = Actions3.fromJSON(actions).hash;
|
|
22366
|
+
return Actions3.updateSequenceState(actionState, actionHash);
|
|
21592
22367
|
}
|
|
21593
22368
|
async function makeGraphqlRequest(query, graphqlEndpoint = networkConfig.minaEndpoint, fallbackEndpoints, { timeout = defaultTimeout } = {}) {
|
|
21594
22369
|
if (graphqlEndpoint === "none")
|
|
@@ -22430,10 +23205,10 @@ async function LocalBlockchain({ proofsEnabled = true, enforceTransactionLimits
|
|
|
22430
23205
|
}
|
|
22431
23206
|
let storedActions = actions[addr]?.[tokenId];
|
|
22432
23207
|
let latestActionState_ = storedActions?.[storedActions.length - 1]?.hash;
|
|
22433
|
-
let latestActionState = latestActionState_ !== void 0 ? Field4(latestActionState_) :
|
|
23208
|
+
let latestActionState = latestActionState_ !== void 0 ? Field4(latestActionState_) : Actions3.emptyActionState();
|
|
22434
23209
|
actions[addr] ??= {};
|
|
22435
23210
|
if (p3.body.actions.data.length > 0) {
|
|
22436
|
-
let newActionState =
|
|
23211
|
+
let newActionState = Actions3.updateSequenceState(latestActionState, p3.body.actions.hash);
|
|
22437
23212
|
actions[addr][tokenId] ??= [];
|
|
22438
23213
|
actions[addr][tokenId].push({
|
|
22439
23214
|
actions: pJson.body.actions,
|
|
@@ -22499,7 +23274,7 @@ ${pendingTransaction2.errors.join("\n")}`);
|
|
|
22499
23274
|
getActions(publicKey, actionStates, tokenId = TokenId4.default) {
|
|
22500
23275
|
let currentActions = actions?.[publicKey.toBase58()]?.[TokenId4.toBase58(tokenId)] ?? [];
|
|
22501
23276
|
let { fromActionState, endActionState } = actionStates ?? {};
|
|
22502
|
-
let emptyState =
|
|
23277
|
+
let emptyState = Actions3.emptyActionState();
|
|
22503
23278
|
if (endActionState?.equals(emptyState).toBoolean())
|
|
22504
23279
|
return [];
|
|
22505
23280
|
let start = fromActionState?.equals(emptyState).toBoolean() ? void 0 : fromActionState?.toString();
|
|
@@ -23197,7 +23972,7 @@ function getStateContexts(sc) {
|
|
|
23197
23972
|
// dist/node/lib/mina/actions/reducer.js
|
|
23198
23973
|
var Reducer = Object.defineProperty(function(reducer) {
|
|
23199
23974
|
return reducer;
|
|
23200
|
-
}, "initialActionState", { get:
|
|
23975
|
+
}, "initialActionState", { get: Actions3.emptyActionState });
|
|
23201
23976
|
function getReducer(contract) {
|
|
23202
23977
|
let reducer = (contract._ ??= {}).reducer;
|
|
23203
23978
|
if (reducer === void 0)
|
|
@@ -23210,7 +23985,7 @@ class ${contract.constructor.name} extends SmartContract {
|
|
|
23210
23985
|
dispatch(action) {
|
|
23211
23986
|
let accountUpdate = contract.self;
|
|
23212
23987
|
let eventFields = reducer.actionType.toFields(action);
|
|
23213
|
-
accountUpdate.body.actions =
|
|
23988
|
+
accountUpdate.body.actions = Actions3.pushEvent(accountUpdate.body.actions, eventFields);
|
|
23214
23989
|
},
|
|
23215
23990
|
reduce(actionLists, stateType, reduce, state3, { maxUpdatesWithActions = 32, maxActionsPerUpdate = 1, skipActionStatePrecondition = false } = {}) {
|
|
23216
23991
|
Provable.asProver(() => {
|
|
@@ -23255,17 +24030,17 @@ class ${contract.constructor.name} extends SmartContract {
|
|
|
23255
24030
|
},
|
|
23256
24031
|
getActions(config) {
|
|
23257
24032
|
const Action = reducer.actionType;
|
|
23258
|
-
const emptyHash2 =
|
|
23259
|
-
const nextHash = (hash3, action) =>
|
|
24033
|
+
const emptyHash2 = Actions3.empty().hash;
|
|
24034
|
+
const nextHash = (hash3, action) => Actions3.pushEvent({ hash: hash3, data: [] }, Action.toFields(action)).hash;
|
|
23260
24035
|
class ActionList2 extends MerkleList.create(Action, nextHash, emptyHash2) {
|
|
23261
24036
|
}
|
|
23262
24037
|
class MerkleActions extends MerkleList.create(
|
|
23263
24038
|
ActionList2.provable,
|
|
23264
|
-
(hash3, actions2) =>
|
|
24039
|
+
(hash3, actions2) => Actions3.updateSequenceState(hash3, actions2.hash),
|
|
23265
24040
|
// if no "start" action hash was specified, this means we are fetching the entire history of actions, which started from the empty action state hash
|
|
23266
24041
|
// otherwise we are only fetching a part of the history, which starts at `fromActionState`
|
|
23267
24042
|
// TODO does this show that `emptyHash` should be part of the instance, not the class? that would make the provable representation bigger though
|
|
23268
|
-
config?.fromActionState ??
|
|
24043
|
+
config?.fromActionState ?? Actions3.emptyActionState()
|
|
23269
24044
|
) {
|
|
23270
24045
|
}
|
|
23271
24046
|
let actions = Provable.witness(MerkleActions.provable, () => {
|
|
@@ -23860,7 +24635,7 @@ class ${this.constructor.name} extends SmartContract {
|
|
|
23860
24635
|
} else {
|
|
23861
24636
|
eventFields = [Field4(eventNumber), ...eventType.toFields(event)];
|
|
23862
24637
|
}
|
|
23863
|
-
accountUpdate.body.events =
|
|
24638
|
+
accountUpdate.body.events = Events3.pushEvent(accountUpdate.body.events, eventFields);
|
|
23864
24639
|
}
|
|
23865
24640
|
/**
|
|
23866
24641
|
* Asynchronously fetches events emitted by this {@link SmartContract} and returns an array of events with their corresponding types.
|
|
@@ -24485,192 +25260,6 @@ function fillWithNull([...values], length) {
|
|
|
24485
25260
|
return values;
|
|
24486
25261
|
}
|
|
24487
25262
|
|
|
24488
|
-
// dist/node/lib/provable/merkle-tree.js
|
|
24489
|
-
var MerkleTree = class _MerkleTree {
|
|
24490
|
-
/**
|
|
24491
|
-
* Creates a new, empty [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
|
24492
|
-
* @param height The height of Merkle Tree.
|
|
24493
|
-
* @returns A new MerkleTree
|
|
24494
|
-
*/
|
|
24495
|
-
constructor(height) {
|
|
24496
|
-
this.height = height;
|
|
24497
|
-
this.nodes = {};
|
|
24498
|
-
this.zeroes = new Array(height);
|
|
24499
|
-
this.zeroes[0] = Field4(0);
|
|
24500
|
-
for (let i = 1; i < height; i += 1) {
|
|
24501
|
-
this.zeroes[i] = Poseidon2.hash([this.zeroes[i - 1], this.zeroes[i - 1]]);
|
|
24502
|
-
}
|
|
24503
|
-
}
|
|
24504
|
-
/**
|
|
24505
|
-
* Return a new MerkleTree with the same contents as this one.
|
|
24506
|
-
*/
|
|
24507
|
-
clone() {
|
|
24508
|
-
let newTree = new _MerkleTree(this.height);
|
|
24509
|
-
for (let [level, nodes] of Object.entries(this.nodes)) {
|
|
24510
|
-
newTree.nodes[level] = { ...nodes };
|
|
24511
|
-
}
|
|
24512
|
-
return newTree;
|
|
24513
|
-
}
|
|
24514
|
-
/**
|
|
24515
|
-
* Returns a node which lives at a given index and level.
|
|
24516
|
-
* @param level Level of the node.
|
|
24517
|
-
* @param index Index of the node.
|
|
24518
|
-
* @returns The data of the node.
|
|
24519
|
-
*/
|
|
24520
|
-
getNode(level, index) {
|
|
24521
|
-
return this.nodes[level]?.[index.toString()] ?? this.zeroes[level];
|
|
24522
|
-
}
|
|
24523
|
-
/**
|
|
24524
|
-
* Returns a leaf at a given index.
|
|
24525
|
-
* @param index Index of the leaf.
|
|
24526
|
-
* @returns The data of the leaf.
|
|
24527
|
-
*/
|
|
24528
|
-
getLeaf(key) {
|
|
24529
|
-
return this.getNode(0, key);
|
|
24530
|
-
}
|
|
24531
|
-
/**
|
|
24532
|
-
* Returns the root of the [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
|
24533
|
-
* @returns The root of the Merkle Tree.
|
|
24534
|
-
*/
|
|
24535
|
-
getRoot() {
|
|
24536
|
-
return this.getNode(this.height - 1, 0n);
|
|
24537
|
-
}
|
|
24538
|
-
// TODO: this allows to set a node at an index larger than the size. OK?
|
|
24539
|
-
setNode(level, index, value) {
|
|
24540
|
-
(this.nodes[level] ??= {})[index.toString()] = value;
|
|
24541
|
-
}
|
|
24542
|
-
// TODO: if this is passed an index bigger than the max, it will set a couple of out-of-bounds nodes but not affect the real Merkle root. OK?
|
|
24543
|
-
/**
|
|
24544
|
-
* Sets the value of a leaf node at a given index to a given value.
|
|
24545
|
-
* @param index Position of the leaf node.
|
|
24546
|
-
* @param leaf New value.
|
|
24547
|
-
*/
|
|
24548
|
-
setLeaf(index, leaf) {
|
|
24549
|
-
if (index >= this.leafCount) {
|
|
24550
|
-
throw new Error(`index ${index} is out of range for ${this.leafCount} leaves.`);
|
|
24551
|
-
}
|
|
24552
|
-
this.setNode(0, index, leaf);
|
|
24553
|
-
let currIndex = index;
|
|
24554
|
-
for (let level = 1; level < this.height; level++) {
|
|
24555
|
-
currIndex /= 2n;
|
|
24556
|
-
const left = this.getNode(level - 1, currIndex * 2n);
|
|
24557
|
-
const right = this.getNode(level - 1, currIndex * 2n + 1n);
|
|
24558
|
-
this.setNode(level, currIndex, Poseidon2.hash([left, right]));
|
|
24559
|
-
}
|
|
24560
|
-
}
|
|
24561
|
-
/**
|
|
24562
|
-
* Returns the witness (also known as [Merkle Proof or Merkle Witness](https://computersciencewiki.org/index.php/Merkle_proof)) for the leaf at the given index.
|
|
24563
|
-
* @param index Position of the leaf node.
|
|
24564
|
-
* @returns The witness that belongs to the leaf.
|
|
24565
|
-
*/
|
|
24566
|
-
getWitness(index) {
|
|
24567
|
-
if (index >= this.leafCount) {
|
|
24568
|
-
throw new Error(`index ${index} is out of range for ${this.leafCount} leaves.`);
|
|
24569
|
-
}
|
|
24570
|
-
const witness2 = [];
|
|
24571
|
-
for (let level = 0; level < this.height - 1; level++) {
|
|
24572
|
-
const isLeft = index % 2n === 0n;
|
|
24573
|
-
const sibling = this.getNode(level, isLeft ? index + 1n : index - 1n);
|
|
24574
|
-
witness2.push({ isLeft, sibling });
|
|
24575
|
-
index /= 2n;
|
|
24576
|
-
}
|
|
24577
|
-
return witness2;
|
|
24578
|
-
}
|
|
24579
|
-
// TODO: this will always return true if the merkle tree was constructed normally; seems to be only useful for testing. remove?
|
|
24580
|
-
/**
|
|
24581
|
-
* Checks if the witness that belongs to the leaf at the given index is a valid witness.
|
|
24582
|
-
* @param index Position of the leaf node.
|
|
24583
|
-
* @returns True if the witness for the leaf node is valid.
|
|
24584
|
-
*/
|
|
24585
|
-
validate(index) {
|
|
24586
|
-
const path = this.getWitness(index);
|
|
24587
|
-
let hash3 = this.getNode(0, index);
|
|
24588
|
-
for (const node of path) {
|
|
24589
|
-
hash3 = Poseidon2.hash(node.isLeft ? [hash3, node.sibling] : [node.sibling, hash3]);
|
|
24590
|
-
}
|
|
24591
|
-
return hash3.toString() === this.getRoot().toString();
|
|
24592
|
-
}
|
|
24593
|
-
// TODO: should this take an optional offset? should it fail if the array is too long?
|
|
24594
|
-
/**
|
|
24595
|
-
* Fills all leaves of the tree.
|
|
24596
|
-
* @param leaves Values to fill the leaves with.
|
|
24597
|
-
*/
|
|
24598
|
-
fill(leaves) {
|
|
24599
|
-
leaves.forEach((value, index) => {
|
|
24600
|
-
this.setLeaf(BigInt(index), value);
|
|
24601
|
-
});
|
|
24602
|
-
}
|
|
24603
|
-
/**
|
|
24604
|
-
* Returns the amount of leaf nodes.
|
|
24605
|
-
* @returns Amount of leaf nodes.
|
|
24606
|
-
*/
|
|
24607
|
-
get leafCount() {
|
|
24608
|
-
return 2n ** BigInt(this.height - 1);
|
|
24609
|
-
}
|
|
24610
|
-
};
|
|
24611
|
-
var BaseMerkleWitness = class extends CircuitValue {
|
|
24612
|
-
height() {
|
|
24613
|
-
return this.constructor.height;
|
|
24614
|
-
}
|
|
24615
|
-
/**
|
|
24616
|
-
* Takes a {@link Witness} and turns it into a circuit-compatible Witness.
|
|
24617
|
-
* @param witness Witness.
|
|
24618
|
-
* @returns A circuit-compatible Witness.
|
|
24619
|
-
*/
|
|
24620
|
-
constructor(witness2) {
|
|
24621
|
-
super();
|
|
24622
|
-
let height = witness2.length + 1;
|
|
24623
|
-
if (height !== this.height()) {
|
|
24624
|
-
throw Error(`Length of witness ${height}-1 doesn't match static tree height ${this.height()}.`);
|
|
24625
|
-
}
|
|
24626
|
-
this.path = witness2.map((item) => item.sibling);
|
|
24627
|
-
this.isLeft = witness2.map((item) => Bool4(item.isLeft));
|
|
24628
|
-
}
|
|
24629
|
-
/**
|
|
24630
|
-
* Calculates a root depending on the leaf value.
|
|
24631
|
-
* @param leaf Value of the leaf node that belongs to this Witness.
|
|
24632
|
-
* @returns The calculated root.
|
|
24633
|
-
*/
|
|
24634
|
-
calculateRoot(leaf) {
|
|
24635
|
-
let hash3 = leaf;
|
|
24636
|
-
let n = this.height();
|
|
24637
|
-
for (let i = 1; i < n; ++i) {
|
|
24638
|
-
let isLeft = this.isLeft[i - 1];
|
|
24639
|
-
const [left, right] = maybeSwap(isLeft, hash3, this.path[i - 1]);
|
|
24640
|
-
hash3 = Poseidon2.hash([left, right]);
|
|
24641
|
-
}
|
|
24642
|
-
return hash3;
|
|
24643
|
-
}
|
|
24644
|
-
/**
|
|
24645
|
-
* Calculates the index of the leaf node that belongs to this Witness.
|
|
24646
|
-
* @returns Index of the leaf.
|
|
24647
|
-
*/
|
|
24648
|
-
calculateIndex() {
|
|
24649
|
-
let powerOfTwo = Field4(1);
|
|
24650
|
-
let index = Field4(0);
|
|
24651
|
-
let n = this.height();
|
|
24652
|
-
for (let i = 1; i < n; ++i) {
|
|
24653
|
-
index = Provable.if(this.isLeft[i - 1], index, index.add(powerOfTwo));
|
|
24654
|
-
powerOfTwo = powerOfTwo.mul(2);
|
|
24655
|
-
}
|
|
24656
|
-
return index;
|
|
24657
|
-
}
|
|
24658
|
-
};
|
|
24659
|
-
function MerkleWitness(height) {
|
|
24660
|
-
class MerkleWitness_ extends BaseMerkleWitness {
|
|
24661
|
-
}
|
|
24662
|
-
MerkleWitness_.height = height;
|
|
24663
|
-
arrayProp(Field4, height - 1)(MerkleWitness_.prototype, "path");
|
|
24664
|
-
arrayProp(Bool4, height - 1)(MerkleWitness_.prototype, "isLeft");
|
|
24665
|
-
return MerkleWitness_;
|
|
24666
|
-
}
|
|
24667
|
-
function maybeSwap(b2, x, y) {
|
|
24668
|
-
let m = b2.toField().mul(x.sub(y));
|
|
24669
|
-
const x_ = y.add(m);
|
|
24670
|
-
const y_ = x.sub(m);
|
|
24671
|
-
return [x_, y_];
|
|
24672
|
-
}
|
|
24673
|
-
|
|
24674
25263
|
// dist/node/lib/provable/merkle-map.js
|
|
24675
25264
|
var import_tslib6 = require("tslib");
|
|
24676
25265
|
var MerkleMap = class {
|
|
@@ -25080,7 +25669,7 @@ function pushAction(actionsHash, action) {
|
|
|
25080
25669
|
MerkleLeaf.hash(action)
|
|
25081
25670
|
]);
|
|
25082
25671
|
}
|
|
25083
|
-
var ActionList = class extends MerkleList.create(MerkleLeaf, pushAction,
|
|
25672
|
+
var ActionList = class extends MerkleList.create(MerkleLeaf, pushAction, Actions3.empty().hash) {
|
|
25084
25673
|
};
|
|
25085
25674
|
var LinearizedAction = class extends Struct({
|
|
25086
25675
|
action: MerkleLeaf,
|
|
@@ -25110,15 +25699,15 @@ var LinearizedAction = class extends Struct({
|
|
|
25110
25699
|
])[0];
|
|
25111
25700
|
}
|
|
25112
25701
|
};
|
|
25113
|
-
var LinearizedActionList = class extends MerkleList.create(LinearizedAction, (hash3, action) => Poseidon2.hash([hash3, LinearizedAction.hash(action)]),
|
|
25702
|
+
var LinearizedActionList = class extends MerkleList.create(LinearizedAction, (hash3, action) => Poseidon2.hash([hash3, LinearizedAction.hash(action)]), Actions3.empty().hash) {
|
|
25114
25703
|
};
|
|
25115
25704
|
async function fetchMerkleLeaves(contract, config) {
|
|
25116
25705
|
class MerkleActions extends MerkleList.create(
|
|
25117
25706
|
ActionList.provable,
|
|
25118
|
-
(hash3, actions) =>
|
|
25707
|
+
(hash3, actions) => Actions3.updateSequenceState(hash3, actions.hash),
|
|
25119
25708
|
// if no "start" action hash was specified, this means we are fetching the entire history of actions, which started from the empty action state hash
|
|
25120
25709
|
// otherwise we are only fetching a part of the history, which starts at `fromActionState`
|
|
25121
|
-
config?.fromActionState ??
|
|
25710
|
+
config?.fromActionState ?? Actions3.emptyActionState()
|
|
25122
25711
|
) {
|
|
25123
25712
|
}
|
|
25124
25713
|
let result = await fetchActions(contract.address, config, contract.tokenId);
|
|
@@ -25127,12 +25716,12 @@ async function fetchMerkleLeaves(contract, config) {
|
|
|
25127
25716
|
let merkleLeafs = result.map((event) => event.actions.map((action) => MerkleLeaf.fromAction(action.map(Field4))));
|
|
25128
25717
|
return MerkleActions.from(merkleLeafs.map((a2) => ActionList.fromReverse(a2)));
|
|
25129
25718
|
}
|
|
25130
|
-
async function fetchMerkleMap(contract, endActionState) {
|
|
25719
|
+
async function fetchMerkleMap(height, contract, endActionState) {
|
|
25131
25720
|
let result = await fetchActions(contract.address, { endActionState }, contract.tokenId);
|
|
25132
25721
|
if ("error" in result)
|
|
25133
25722
|
throw Error(JSON.stringify(result));
|
|
25134
25723
|
let leaves = result.map((event) => event.actions.map((action) => MerkleLeaf.fromAction(action.map(Field4))).reverse());
|
|
25135
|
-
let merkleMap = new
|
|
25724
|
+
let merkleMap = new (IndexedMerkleMap(height))();
|
|
25136
25725
|
let valueMap = /* @__PURE__ */ new Map();
|
|
25137
25726
|
updateMerkleMap(leaves, merkleMap, valueMap);
|
|
25138
25727
|
return { merkleMap, valueMap };
|
|
@@ -25144,22 +25733,23 @@ function updateMerkleMap(updates, tree, valueMap) {
|
|
|
25144
25733
|
let updates2 = [];
|
|
25145
25734
|
for (let leaf of leaves) {
|
|
25146
25735
|
let { key, value, usesPreviousValue, previousValue, prefix } = MerkleLeaf.toValue(leaf);
|
|
25147
|
-
let
|
|
25736
|
+
let previous = intermediateTree.getOption(key).orElse(0n);
|
|
25737
|
+
let isValidAction = !usesPreviousValue || previous.toBigInt() === previousValue;
|
|
25148
25738
|
if (!isValidAction) {
|
|
25149
25739
|
isValidUpdate = false;
|
|
25150
25740
|
break;
|
|
25151
25741
|
}
|
|
25152
|
-
intermediateTree.
|
|
25153
|
-
updates2.push({ key,
|
|
25742
|
+
intermediateTree.set(key, value);
|
|
25743
|
+
updates2.push({ key, fullValue: prefix.get() });
|
|
25154
25744
|
}
|
|
25155
25745
|
if (isValidUpdate) {
|
|
25156
|
-
|
|
25157
|
-
|
|
25746
|
+
tree.overwrite(intermediateTree);
|
|
25747
|
+
for (let { key, fullValue } of updates2) {
|
|
25158
25748
|
if (valueMap)
|
|
25159
25749
|
valueMap.set(key, fullValue);
|
|
25160
25750
|
}
|
|
25161
25751
|
} else {
|
|
25162
|
-
intermediateTree
|
|
25752
|
+
intermediateTree.overwrite(tree);
|
|
25163
25753
|
}
|
|
25164
25754
|
}
|
|
25165
25755
|
}
|
|
@@ -25179,21 +25769,18 @@ var OffchainStateCommitments = class _OffchainStateCommitments extends Struct({
|
|
|
25179
25769
|
// actionState: ActionIterator.provable,
|
|
25180
25770
|
actionState: Field4
|
|
25181
25771
|
}) {
|
|
25182
|
-
static
|
|
25183
|
-
let emptyMerkleRoot = new
|
|
25772
|
+
static emptyFromHeight(height) {
|
|
25773
|
+
let emptyMerkleRoot = new (IndexedMerkleMap(height))().root;
|
|
25184
25774
|
return new _OffchainStateCommitments({
|
|
25185
25775
|
root: emptyMerkleRoot,
|
|
25186
25776
|
actionState: Actions.emptyActionState()
|
|
25187
25777
|
});
|
|
25188
25778
|
}
|
|
25189
25779
|
};
|
|
25190
|
-
|
|
25191
|
-
var MerkleMapWitness2 = class extends MerkleWitness(TREE_HEIGHT) {
|
|
25192
|
-
};
|
|
25193
|
-
function merkleUpdateBatch({ maxActionsPerBatch, maxActionsPerUpdate }, stateA, actions, tree) {
|
|
25780
|
+
function merkleUpdateBatch({ maxActionsPerProof, maxActionsPerUpdate }, stateA, actions, tree) {
|
|
25194
25781
|
actions.currentHash.assertEquals(stateA.actionState);
|
|
25195
25782
|
let linearActions = LinearizedActionList.empty();
|
|
25196
|
-
for (let i = 0; i <
|
|
25783
|
+
for (let i = 0; i < maxActionsPerProof; i++) {
|
|
25197
25784
|
let inner = actions.next().startIterating();
|
|
25198
25785
|
let isAtEnd = Bool4(false);
|
|
25199
25786
|
for (let i2 = 0; i2 < maxActionsPerUpdate; i2++) {
|
|
@@ -25208,55 +25795,43 @@ function merkleUpdateBatch({ maxActionsPerBatch, maxActionsPerUpdate }, stateA,
|
|
|
25208
25795
|
inner.assertAtEnd(`Expected at most ${maxActionsPerUpdate} actions per account update.`);
|
|
25209
25796
|
}
|
|
25210
25797
|
actions.assertAtEnd();
|
|
25211
|
-
|
|
25212
|
-
let
|
|
25213
|
-
let intermediateUpdates = [];
|
|
25214
|
-
let intermediateTree = Unconstrained.witness(() => tree.get().clone());
|
|
25798
|
+
stateA.root.assertEquals(tree.root);
|
|
25799
|
+
let intermediateTree = tree.clone();
|
|
25215
25800
|
let isValidUpdate = Bool4(true);
|
|
25216
|
-
linearActions.forEach(
|
|
25801
|
+
linearActions.forEach(maxActionsPerProof, (element, isDummy) => {
|
|
25217
25802
|
let { action, isCheckPoint } = element;
|
|
25218
25803
|
let { key, value, usesPreviousValue, previousValue } = action;
|
|
25219
|
-
|
|
25220
|
-
|
|
25221
|
-
|
|
25222
|
-
|
|
25223
|
-
let matchesPreviousValue = actualPreviousValue.equals(previousValue);
|
|
25804
|
+
key = Provable.if(isDummy, Field4(0n), key);
|
|
25805
|
+
value = Provable.if(isDummy, Field4(0n), value);
|
|
25806
|
+
let actualPreviousValue = intermediateTree.set(key, value);
|
|
25807
|
+
let matchesPreviousValue = actualPreviousValue.orElse(0n).equals(previousValue);
|
|
25224
25808
|
let isValidAction = usesPreviousValue.implies(matchesPreviousValue);
|
|
25225
25809
|
isValidUpdate = isValidUpdate.and(isValidAction);
|
|
25226
|
-
|
|
25227
|
-
intermediateRoot = Provable.if(isDummy, intermediateRoot, newRoot);
|
|
25228
|
-
root = Provable.if(isCheckPoint.and(isValidUpdate), intermediateRoot, root);
|
|
25229
|
-
let wasValidUpdate = isValidUpdate;
|
|
25810
|
+
tree.overwriteIf(isCheckPoint.and(isValidUpdate), intermediateTree);
|
|
25230
25811
|
isValidUpdate = Provable.if(isCheckPoint, Bool4(true), isValidUpdate);
|
|
25231
|
-
|
|
25232
|
-
Provable.asProver(() => {
|
|
25233
|
-
if (isDummy.toBoolean())
|
|
25234
|
-
return;
|
|
25235
|
-
intermediateTree.get().setLeaf(key.toBigInt(), value.toConstant());
|
|
25236
|
-
intermediateUpdates.push({ key, value });
|
|
25237
|
-
if (isCheckPoint.toBoolean()) {
|
|
25238
|
-
if (wasValidUpdate.toBoolean()) {
|
|
25239
|
-
intermediateUpdates.forEach(({ key: key2, value: value2 }) => {
|
|
25240
|
-
tree.get().setLeaf(key2.toBigInt(), value2.toConstant());
|
|
25241
|
-
});
|
|
25242
|
-
} else {
|
|
25243
|
-
intermediateTree.set(tree.get().clone());
|
|
25244
|
-
}
|
|
25245
|
-
intermediateUpdates = [];
|
|
25246
|
-
}
|
|
25247
|
-
});
|
|
25812
|
+
intermediateTree.overwriteIf(isCheckPoint, tree);
|
|
25248
25813
|
});
|
|
25249
|
-
return { root, actionState: actions.currentHash };
|
|
25814
|
+
return { root: tree.root, actionState: actions.currentHash };
|
|
25250
25815
|
}
|
|
25251
25816
|
function OffchainStateRollup({
|
|
25252
|
-
|
|
25253
|
-
|
|
25254
|
-
|
|
25255
|
-
|
|
25256
|
-
|
|
25257
|
-
|
|
25258
|
-
|
|
25817
|
+
/**
|
|
25818
|
+
* the constraints used in one batch proof with a height-31 tree are:
|
|
25819
|
+
*
|
|
25820
|
+
* 1967*A + 87*A*U + 2
|
|
25821
|
+
*
|
|
25822
|
+
* where A = maxActionsPerProof and U = maxActionsPerUpdate.
|
|
25823
|
+
*
|
|
25824
|
+
* To determine defaults, we set U=4 which should cover most use cases while ensuring
|
|
25825
|
+
* that the main loop which is independent of U dominates.
|
|
25826
|
+
*
|
|
25827
|
+
* Targeting ~50k constraints, to leave room for recursive verification, yields A=22.
|
|
25828
|
+
*/
|
|
25829
|
+
maxActionsPerProof = 22,
|
|
25830
|
+
maxActionsPerUpdate = 4,
|
|
25831
|
+
logTotalCapacity = 30
|
|
25259
25832
|
} = {}) {
|
|
25833
|
+
class IndexedMerkleMapN extends IndexedMerkleMap(logTotalCapacity + 1) {
|
|
25834
|
+
}
|
|
25260
25835
|
let offchainStateRollup = ZkProgram({
|
|
25261
25836
|
name: "merkle-map-rollup",
|
|
25262
25837
|
publicInput: OffchainStateCommitments,
|
|
@@ -25267,9 +25842,9 @@ function OffchainStateRollup({
|
|
|
25267
25842
|
*/
|
|
25268
25843
|
firstBatch: {
|
|
25269
25844
|
// [actions, tree]
|
|
25270
|
-
privateInputs: [ActionIterator.provable,
|
|
25845
|
+
privateInputs: [ActionIterator.provable, IndexedMerkleMapN.provable],
|
|
25271
25846
|
async method(stateA, actions, tree) {
|
|
25272
|
-
return merkleUpdateBatch({
|
|
25847
|
+
return merkleUpdateBatch({ maxActionsPerProof, maxActionsPerUpdate }, stateA, actions, tree);
|
|
25273
25848
|
}
|
|
25274
25849
|
},
|
|
25275
25850
|
/**
|
|
@@ -25279,14 +25854,14 @@ function OffchainStateRollup({
|
|
|
25279
25854
|
// [actions, tree, proof]
|
|
25280
25855
|
privateInputs: [
|
|
25281
25856
|
ActionIterator.provable,
|
|
25282
|
-
|
|
25857
|
+
IndexedMerkleMapN.provable,
|
|
25283
25858
|
SelfProof
|
|
25284
25859
|
],
|
|
25285
25860
|
async method(stateA, actions, tree, recursiveProof) {
|
|
25286
25861
|
recursiveProof.verify();
|
|
25287
25862
|
Provable.assertEqual(OffchainStateCommitments, recursiveProof.publicInput, stateA);
|
|
25288
25863
|
let stateB = recursiveProof.publicOutput;
|
|
25289
|
-
return merkleUpdateBatch({
|
|
25864
|
+
return merkleUpdateBatch({ maxActionsPerProof, maxActionsPerUpdate }, stateB, actions, tree);
|
|
25290
25865
|
}
|
|
25291
25866
|
}
|
|
25292
25867
|
}
|
|
@@ -25304,34 +25879,38 @@ function OffchainStateRollup({
|
|
|
25304
25879
|
return result;
|
|
25305
25880
|
},
|
|
25306
25881
|
async prove(tree, actions) {
|
|
25307
|
-
assert3(tree.height ===
|
|
25882
|
+
assert3(tree.height === logTotalCapacity + 1, "Tree height must match");
|
|
25308
25883
|
if (getProofsEnabled())
|
|
25309
25884
|
await this.compile();
|
|
25310
25885
|
tree = tree.clone();
|
|
25311
25886
|
let iterator = actions.startIterating();
|
|
25312
25887
|
let inputState = new OffchainStateCommitments({
|
|
25313
|
-
root: tree.
|
|
25888
|
+
root: tree.root,
|
|
25314
25889
|
actionState: iterator.currentHash
|
|
25315
25890
|
});
|
|
25316
25891
|
if (!getProofsEnabled()) {
|
|
25317
25892
|
let actionsList = actions.data.get().map(({ element: actionsList2 }) => actionsList2.data.get().map(({ element }) => element).reverse()).reverse();
|
|
25318
25893
|
updateMerkleMap(actionsList, tree);
|
|
25319
25894
|
let finalState = new OffchainStateCommitments({
|
|
25320
|
-
root: tree.
|
|
25895
|
+
root: tree.root,
|
|
25321
25896
|
actionState: iterator.hash
|
|
25322
25897
|
});
|
|
25323
25898
|
let proof2 = await RollupProof.dummy(inputState, finalState, 2, 15);
|
|
25324
25899
|
return { proof: proof2, tree, nProofs: 0 };
|
|
25325
25900
|
}
|
|
25326
|
-
let slice = sliceActions(iterator,
|
|
25327
|
-
let proof = await offchainStateRollup.firstBatch(inputState, slice,
|
|
25901
|
+
let slice = sliceActions(iterator, maxActionsPerProof);
|
|
25902
|
+
let proof = await offchainStateRollup.firstBatch(inputState, slice, tree);
|
|
25903
|
+
tree.root = proof.publicOutput.root;
|
|
25904
|
+
tree.length = Field4(tree.data.get().sortedLeaves.length);
|
|
25328
25905
|
let nProofs = 1;
|
|
25329
25906
|
for (let i = 1; ; i++) {
|
|
25330
25907
|
if (iterator.isAtEnd().toBoolean())
|
|
25331
25908
|
break;
|
|
25332
25909
|
nProofs++;
|
|
25333
|
-
let slice2 = sliceActions(iterator,
|
|
25334
|
-
proof = await offchainStateRollup.nextBatch(inputState, slice2,
|
|
25910
|
+
let slice2 = sliceActions(iterator, maxActionsPerProof);
|
|
25911
|
+
proof = await offchainStateRollup.nextBatch(inputState, slice2, tree, proof);
|
|
25912
|
+
tree.root = proof.publicOutput.root;
|
|
25913
|
+
tree.length = Field4(tree.data.get().sortedLeaves.length);
|
|
25335
25914
|
}
|
|
25336
25915
|
return { proof, tree, nProofs };
|
|
25337
25916
|
}
|
|
@@ -25358,14 +25937,17 @@ function sliceActions(actions, batchSize) {
|
|
|
25358
25937
|
}
|
|
25359
25938
|
|
|
25360
25939
|
// dist/node/lib/mina/actions/offchain-state.js
|
|
25361
|
-
|
|
25362
|
-
|
|
25940
|
+
function OffchainState(config, options) {
|
|
25941
|
+
let { logTotalCapacity = 30, maxActionsPerUpdate = 4, maxActionsPerProof } = options ?? {};
|
|
25942
|
+
const height = logTotalCapacity + 1;
|
|
25943
|
+
class IndexedMerkleMapN extends IndexedMerkleMap(height) {
|
|
25944
|
+
}
|
|
25363
25945
|
let internal = {
|
|
25364
25946
|
_contract: void 0,
|
|
25365
25947
|
_merkleMap: void 0,
|
|
25366
25948
|
_valueMap: void 0,
|
|
25367
25949
|
get contract() {
|
|
25368
|
-
assert3(internal._contract !== void 0, "Must call `
|
|
25950
|
+
assert3(internal._contract !== void 0, "Must call `setContractInstance()` first");
|
|
25369
25951
|
return internal._contract;
|
|
25370
25952
|
}
|
|
25371
25953
|
};
|
|
@@ -25379,12 +25961,16 @@ function OffchainState(config) {
|
|
|
25379
25961
|
return { merkleMap: internal._merkleMap, valueMap: internal._valueMap };
|
|
25380
25962
|
}
|
|
25381
25963
|
let actionState = await onchainActionState();
|
|
25382
|
-
let { merkleMap, valueMap } = await fetchMerkleMap(internal.contract, actionState);
|
|
25964
|
+
let { merkleMap, valueMap } = await fetchMerkleMap(height, internal.contract, actionState);
|
|
25383
25965
|
internal._merkleMap = merkleMap;
|
|
25384
25966
|
internal._valueMap = valueMap;
|
|
25385
25967
|
return { merkleMap, valueMap };
|
|
25386
25968
|
};
|
|
25387
|
-
let rollup = OffchainStateRollup(
|
|
25969
|
+
let rollup = OffchainStateRollup({
|
|
25970
|
+
logTotalCapacity,
|
|
25971
|
+
maxActionsPerProof,
|
|
25972
|
+
maxActionsPerUpdate
|
|
25973
|
+
});
|
|
25388
25974
|
function contract() {
|
|
25389
25975
|
let ctx = smartContractContext.get();
|
|
25390
25976
|
assert3(ctx !== null, "Offchain state methods must be called within a contract method");
|
|
@@ -25393,6 +25979,9 @@ function OffchainState(config) {
|
|
|
25393
25979
|
}
|
|
25394
25980
|
async function get2(key, valueType) {
|
|
25395
25981
|
let stateRoot = contract().offchainState.getAndRequireEquals().root;
|
|
25982
|
+
let map2 = await Provable.witnessAsync(IndexedMerkleMapN.provable, async () => (await merkleMaps()).merkleMap);
|
|
25983
|
+
map2.root.assertEquals(stateRoot, "root mismatch");
|
|
25984
|
+
let valueHash = map2.getOption(key);
|
|
25396
25985
|
const optionType = Option(valueType);
|
|
25397
25986
|
let value = await Provable.witnessAsync(optionType, async () => {
|
|
25398
25987
|
let { valueMap } = await merkleMaps();
|
|
@@ -25403,15 +25992,9 @@ function OffchainState(config) {
|
|
|
25403
25992
|
let value2 = fromActionWithoutHashes(valueType, valueFields);
|
|
25404
25993
|
return optionType.from(value2);
|
|
25405
25994
|
});
|
|
25406
|
-
let
|
|
25407
|
-
|
|
25408
|
-
|
|
25409
|
-
});
|
|
25410
|
-
let valueHash = Provable.if(value.isSome, Poseidon2.hashPacked(valueType, value.value), Field4(0));
|
|
25411
|
-
let actualKey = witness2.calculateIndex();
|
|
25412
|
-
let actualRoot = witness2.calculateRoot(valueHash);
|
|
25413
|
-
key.assertEquals(actualKey, "key mismatch");
|
|
25414
|
-
stateRoot.assertEquals(actualRoot, "root mismatch");
|
|
25995
|
+
let hashMatches = Poseidon2.hashPacked(valueType, value.value).equals(valueHash.value);
|
|
25996
|
+
let bothNone = value.isSome.or(valueHash.isSome).not();
|
|
25997
|
+
assert3(hashMatches.or(bothNone), "value hash mismatch");
|
|
25415
25998
|
return value;
|
|
25416
25999
|
}
|
|
25417
26000
|
function field(index, type) {
|
|
@@ -25427,7 +26010,7 @@ function OffchainState(config) {
|
|
|
25427
26010
|
value: type.fromValue(value)
|
|
25428
26011
|
});
|
|
25429
26012
|
let update = contract().self;
|
|
25430
|
-
update.body.actions =
|
|
26013
|
+
update.body.actions = Actions3.pushEvent(update.body.actions, action);
|
|
25431
26014
|
},
|
|
25432
26015
|
update({ from, to }) {
|
|
25433
26016
|
let action = toAction({
|
|
@@ -25439,7 +26022,7 @@ function OffchainState(config) {
|
|
|
25439
26022
|
previousValue: optionType.fromValue(from)
|
|
25440
26023
|
});
|
|
25441
26024
|
let update = contract().self;
|
|
25442
|
-
update.body.actions =
|
|
26025
|
+
update.body.actions = Actions3.pushEvent(update.body.actions, action);
|
|
25443
26026
|
},
|
|
25444
26027
|
async get() {
|
|
25445
26028
|
let key = toKeyHash(prefix, void 0, void 0);
|
|
@@ -25460,7 +26043,7 @@ function OffchainState(config) {
|
|
|
25460
26043
|
value: valueType.fromValue(value)
|
|
25461
26044
|
});
|
|
25462
26045
|
let update = contract().self;
|
|
25463
|
-
update.body.actions =
|
|
26046
|
+
update.body.actions = Actions3.pushEvent(update.body.actions, action);
|
|
25464
26047
|
},
|
|
25465
26048
|
update(key, { from, to }) {
|
|
25466
26049
|
let action = toAction({
|
|
@@ -25472,7 +26055,7 @@ function OffchainState(config) {
|
|
|
25472
26055
|
previousValue: optionType.fromValue(from)
|
|
25473
26056
|
});
|
|
25474
26057
|
let update = contract().self;
|
|
25475
|
-
update.body.actions =
|
|
26058
|
+
update.body.actions = Actions3.pushEvent(update.body.actions, action);
|
|
25476
26059
|
},
|
|
25477
26060
|
async get(key) {
|
|
25478
26061
|
let keyHash = toKeyHash(prefix, keyType, key);
|
|
@@ -25494,7 +26077,7 @@ function OffchainState(config) {
|
|
|
25494
26077
|
fromActionState: actionState
|
|
25495
26078
|
});
|
|
25496
26079
|
let result = await rollup.prove(merkleMap, actions);
|
|
25497
|
-
let { merkleMap: newMerkleMap, valueMap: newValueMap } = await fetchMerkleMap(internal.contract);
|
|
26080
|
+
let { merkleMap: newMerkleMap, valueMap: newValueMap } = await fetchMerkleMap(height, internal.contract);
|
|
25498
26081
|
internal._merkleMap = newMerkleMap;
|
|
25499
26082
|
internal._valueMap = newValueMap;
|
|
25500
26083
|
return result.proof;
|
|
@@ -25510,11 +26093,15 @@ function OffchainState(config) {
|
|
|
25510
26093
|
fields: Object.fromEntries(Object.entries(config).map(([key, kind], i) => [
|
|
25511
26094
|
key,
|
|
25512
26095
|
kind.kind === "offchain-field" ? field(i, kind.type) : map(i, kind.keyType, kind.valueType)
|
|
25513
|
-
]))
|
|
26096
|
+
])),
|
|
26097
|
+
commitments() {
|
|
26098
|
+
return State2(OffchainStateCommitments.emptyFromHeight(height));
|
|
26099
|
+
}
|
|
25514
26100
|
};
|
|
25515
26101
|
}
|
|
25516
26102
|
OffchainState.Map = OffchainMap;
|
|
25517
26103
|
OffchainState.Field = OffchainField;
|
|
26104
|
+
OffchainState.Commitments = OffchainStateCommitments;
|
|
25518
26105
|
function OffchainField(type) {
|
|
25519
26106
|
return { kind: "offchain-field", type };
|
|
25520
26107
|
}
|
|
@@ -25524,11 +26111,13 @@ function OffchainMap(key, value) {
|
|
|
25524
26111
|
|
|
25525
26112
|
// dist/node/index.js
|
|
25526
26113
|
var Experimental_ = {
|
|
25527
|
-
memoizeWitness
|
|
26114
|
+
memoizeWitness,
|
|
26115
|
+
IndexedMerkleMap
|
|
25528
26116
|
};
|
|
25529
26117
|
var Experimental;
|
|
25530
26118
|
(function(Experimental2) {
|
|
25531
26119
|
Experimental2.memoizeWitness = Experimental_.memoizeWitness;
|
|
26120
|
+
Experimental2.IndexedMerkleMap = Experimental_.IndexedMerkleMap;
|
|
25532
26121
|
Experimental2.OffchainState = OffchainState;
|
|
25533
26122
|
class OffchainStateCommitments2 extends OffchainStateCommitments {
|
|
25534
26123
|
}
|