diff --git a/contracts/src/SettlementProof.ts b/contracts/src/SettlementProof.ts index 76eada94..6a2deae9 100644 --- a/contracts/src/SettlementProof.ts +++ b/contracts/src/SettlementProof.ts @@ -202,28 +202,35 @@ const MultisigVerifierProgram = ZkProgram({ 'Skipped block' ); - let counter = Field.from(0); + let accumulatedStake = Field.from(0); + let totalStake = Field.from(0); let list = List.empty(); const signatureMessage = pulsarBlocks.list[i].hash().toFields(); for (let j = 0; j < VALIDATOR_NUMBER; j++) { - const { signature, publicKey } = + const { signature, publicKey, stake } = signaturePublicKeyMatrix.matrix[i].list[j]; const isValid = signature.verify(publicKey, signatureMessage); - counter = Provable.if(isValid, counter.add(1), counter); - - list.push(Poseidon.hash(publicKey.toFields())); + accumulatedStake = Provable.if( + isValid, + accumulatedStake.add(stake), + accumulatedStake + ); + totalStake = totalStake.add(stake); + + list.push(Poseidon.hash([...publicKey.toFields(), stake])); } list.hash.assertEquals( publicInputs.InitialMerkleListRoot, "Validator MerkleList hash doesn't match" ); - counter.assertGreaterThanOrEqual( - // Field.from((VALIDATOR_NUMBER * 2) / 3), - Field(VALIDATOR_NUMBER), - 'Not enough valid signatures' - ); + accumulatedStake + .mul(3) + .assertGreaterThanOrEqual( + totalStake.mul(2), + 'Not enough valid signatures (stake < 2/3)' + ); } return { diff --git a/contracts/src/ValidateReduce.ts b/contracts/src/ValidateReduce.ts index 536dd151..4402f971 100644 --- a/contracts/src/ValidateReduce.ts +++ b/contracts/src/ValidateReduce.ts @@ -61,26 +61,27 @@ const ValidateReduceProgram = ZkProgram({ publicInputs: ValidateReducePublicInput, signaturePublicKeyList: SignaturePublicKeyList ) { - let counter = Field.from(0); + let accumulatedStake = Field.from(0); + let totalStake = Field.from(0); let list = List.empty(); const signatureMessage = publicInputs.hash().toFields(); for (let i = 0; i < VALIDATOR_NUMBER; i++) { - const { signature, publicKey } = signaturePublicKeyList.list[i]; + const { signature, publicKey, stake } = signaturePublicKeyList.list[i]; const isValid = signature.verify(publicKey, signatureMessage); - counter = Provable.if(isValid, counter.add(1), counter); + accumulatedStake = Provable.if(isValid, accumulatedStake.add(stake), accumulatedStake); + totalStake = totalStake.add(stake); - list.push(Poseidon.hash(publicKey.toFields())); + list.push(Poseidon.hash([...publicKey.toFields(), stake])); } list.hash.assertEquals( publicInputs.merkleListRoot, "Validator MerkleList hash doesn't match" ); - counter.assertGreaterThanOrEqual( - // Field.from((VALIDATOR_NUMBER * 2) / 3), - Field.from(1), - 'Not enough valid signatures' + accumulatedStake.mul(3).assertGreaterThanOrEqual( + totalStake.mul(2), + 'Not enough valid signatures (stake < 2/3)' ); }, }, diff --git a/contracts/src/benchmark/benchmark.ts b/contracts/src/benchmark/benchmark.ts index 1d0ee794..4f3edf1b 100644 --- a/contracts/src/benchmark/benchmark.ts +++ b/contracts/src/benchmark/benchmark.ts @@ -251,7 +251,7 @@ async function main() { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = activeSet[i % 60]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } logParams(); @@ -310,7 +310,7 @@ async function main() { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = activeSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } if (testEnvironment === 'local') { diff --git a/contracts/src/test/ActionStack.test.ts b/contracts/src/test/ActionStack.test.ts index 860ed745..b73530de 100644 --- a/contracts/src/test/ActionStack.test.ts +++ b/contracts/src/test/ActionStack.test.ts @@ -37,7 +37,7 @@ describe('Action Stack Proof tests', () => { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = activeSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } }); diff --git a/contracts/src/test/SettlementContract.test.ts b/contracts/src/test/SettlementContract.test.ts index 29a34a34..f3cade29 100644 --- a/contracts/src/test/SettlementContract.test.ts +++ b/contracts/src/test/SettlementContract.test.ts @@ -483,7 +483,7 @@ describe('SettlementProof tests', () => { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = activeSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } if (testEnvironment === 'local') { diff --git a/contracts/src/test/SettlementProof.test.ts b/contracts/src/test/SettlementProof.test.ts index 9bc58100..5e895991 100644 --- a/contracts/src/test/SettlementProof.test.ts +++ b/contracts/src/test/SettlementProof.test.ts @@ -38,7 +38,7 @@ describe('SettlementProof tests', () => { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = validatorSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } }); diff --git a/contracts/src/test/ValidateReduce.test.ts b/contracts/src/test/ValidateReduce.test.ts index 8824ae4c..924ee88d 100644 --- a/contracts/src/test/ValidateReduce.test.ts +++ b/contracts/src/test/ValidateReduce.test.ts @@ -31,7 +31,7 @@ describe('ValidateReduceProof tests', () => { for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = validatorSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } }); diff --git a/contracts/src/test/mock.ts b/contracts/src/test/mock.ts index baacdef1..51e87177 100644 --- a/contracts/src/test/mock.ts +++ b/contracts/src/test/mock.ts @@ -1,4 +1,4 @@ -import { PublicKey, PrivateKey, Poseidon } from 'o1js'; +import { PublicKey, PrivateKey, Poseidon, Field } from 'o1js'; import { List } from '../types/common.js'; import { VALIDATOR_NUMBER } from '../utils/constants.js'; export { devnetTestAccounts, validatorSet, testAccounts, mockValidatorList }; @@ -143,6 +143,6 @@ const testAccounts: Array<[PrivateKey, PublicKey]> = [ const mockValidatorList = validatorSet .slice(0, VALIDATOR_NUMBER) .reduce((acc, v) => { - acc.push(Poseidon.hash(v[1].toFields())); + acc.push(Poseidon.hash([...v[1].toFields(), Field(1)])); return acc; }, List.empty()); diff --git a/contracts/src/types/signaturePubKeyList.ts b/contracts/src/types/signaturePubKeyList.ts index 3b0d6454..c3373eed 100644 --- a/contracts/src/types/signaturePubKeyList.ts +++ b/contracts/src/types/signaturePubKeyList.ts @@ -1,4 +1,4 @@ -import { Provable, PublicKey, Signature, Struct } from 'o1js'; +import { Field, Provable, PublicKey, Signature, Struct } from 'o1js'; import { SETTLEMENT_MATRIX_SIZE, VALIDATOR_NUMBER, @@ -9,16 +9,19 @@ export { SignaturePublicKey, SignaturePublicKeyList, SignaturePublicKeyMatrix }; class SignaturePublicKey extends Struct({ signature: Signature, publicKey: PublicKey, + stake: Field, }) {} class SignaturePublicKeyList extends Struct({ list: Provable.Array(SignaturePublicKey, VALIDATOR_NUMBER), }) { - static fromArray(arr: Array<[Signature, PublicKey]>): SignaturePublicKeyList { + static fromArray( + arr: Array<[Signature, PublicKey, Field]> + ): SignaturePublicKeyList { return new SignaturePublicKeyList({ list: arr.map( - ([signature, publicKey]) => - new SignaturePublicKey({ signature, publicKey }) + ([signature, publicKey, stake]) => + new SignaturePublicKey({ signature, publicKey, stake }) ), }); } @@ -27,6 +30,7 @@ class SignaturePublicKeyList extends Struct({ return this.list.map((item) => ({ signature: item.signature.toString(), publicKey: item.publicKey.toString(), + stake: item.stake.toString(), })); } } @@ -35,7 +39,7 @@ class SignaturePublicKeyMatrix extends Struct({ matrix: Provable.Array(SignaturePublicKeyList, SETTLEMENT_MATRIX_SIZE), }) { static fromArray( - arr: Array> + arr: Array> ): SignaturePublicKeyMatrix { return new SignaturePublicKeyMatrix({ matrix: arr.map((row) => SignaturePublicKeyList.fromArray(row)), diff --git a/contracts/src/utils/testUtils.ts b/contracts/src/utils/testUtils.ts index 0a05692f..111f44ca 100644 --- a/contracts/src/utils/testUtils.ts +++ b/contracts/src/utils/testUtils.ts @@ -65,7 +65,7 @@ function GenerateSignaturePubKeyList( } return SignaturePublicKeyList.fromArray( - signatures.map((signature, i) => [signature, signerSet[i][1]]) + signatures.map((signature, i) => [signature, signerSet[i][1], Field(1)]) ); } @@ -82,7 +82,7 @@ function GenerateSignaturePubKeyMatrix( } return SignaturePublicKeyMatrix.fromArray( signatureMatrix.map((list) => - list.list.map((item) => [item.signature, item.publicKey]) + list.list.map((item) => [item.signature, item.publicKey, item.stake]) ) ); } @@ -100,7 +100,11 @@ function GenerateReducerSignatureList( } return SignaturePublicKeyList.fromArray( - signatures.map((signature, i) => [signature, proofGeneratorsList[i][1]]) + signatures.map((signature, i) => [ + signature, + proofGeneratorsList[i][1], + Field(1), + ]) ); } @@ -111,7 +115,7 @@ function CreateValidatorMerkleList( for (let i = 0; i < validatorSet.length; i++) { const [, publicKey] = validatorSet[i]; - merkleList.push(Poseidon.hash(publicKey.toFields())); + merkleList.push(Poseidon.hash([...publicKey.toFields(), Field(1)])); } return merkleList;