From d68b785fe7b240311b459c823c98f1aa9d2646a2 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:04:12 -0700 Subject: [PATCH 01/11] add devnet to networkId type, update mina defaults to use devnet instead of testnet in instance and localblockchain --- src/lib/mina/local-blockchain.ts | 2 +- src/lib/mina/mina-instance.ts | 2 +- src/lib/mina/mina.ts | 2 +- src/mina-signer/src/types.ts | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/mina/local-blockchain.ts b/src/lib/mina/local-blockchain.ts index 2a80874c32..4d049cac09 100644 --- a/src/lib/mina/local-blockchain.ts +++ b/src/lib/mina/local-blockchain.ts @@ -106,7 +106,7 @@ async function LocalBlockchain({ const originalProofsEnabled = proofsEnabled; return { - getNetworkId: () => 'testnet' as NetworkId, + getNetworkId: () => 'devnet' as NetworkId, proofsEnabled, getNetworkConstants() { return { diff --git a/src/lib/mina/mina-instance.ts b/src/lib/mina/mina-instance.ts index 77bc328ba9..640953936b 100644 --- a/src/lib/mina/mina-instance.ts +++ b/src/lib/mina/mina-instance.ts @@ -117,7 +117,7 @@ let activeInstance: Mina = { fetchActions: noActiveInstance, getActions: noActiveInstance, proofsEnabled: true, - getNetworkId: () => 'testnet', + getNetworkId: () => 'devnet', }; /** diff --git a/src/lib/mina/mina.ts b/src/lib/mina/mina.ts index 67edd659e5..c7ea264848 100644 --- a/src/lib/mina/mina.ts +++ b/src/lib/mina/mina.ts @@ -117,7 +117,7 @@ function Network( } | string ): Mina { - let minaNetworkId: NetworkId = 'testnet'; + let minaNetworkId: NetworkId = 'devnet'; let minaGraphqlEndpoint: string; let archiveEndpoint: string; let lightnetAccountManagerEndpoint: string; diff --git a/src/mina-signer/src/types.ts b/src/mina-signer/src/types.ts index 6eb7e75c80..f3692cf03a 100644 --- a/src/mina-signer/src/types.ts +++ b/src/mina-signer/src/types.ts @@ -9,7 +9,9 @@ export type Field = number | bigint | string; export type PublicKey = string; export type PrivateKey = string; export type Signature = SignatureJson; -export type NetworkId = 'mainnet' | 'testnet' | { custom: string }; + +// testnet is deprecated in favor of devnet +export type NetworkId = 'mainnet' | 'devnet' | 'testnet' | { custom: string }; export const NetworkId = { toString(network: NetworkId) { From 526881d9ee734d076ebbcf58cc078eb438a38cbf Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:33:42 -0700 Subject: [PATCH 02/11] update signatures to treat devnet and testnet as identical --- src/lib/mina/token/forest-iterator.unit-test.ts | 3 ++- src/lib/provable/crypto/signature.ts | 10 +++++----- src/mina-signer/src/signature.ts | 9 ++++++--- src/mina-signer/src/signature.unit-test.ts | 17 +++++++++++------ 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/lib/mina/token/forest-iterator.unit-test.ts b/src/lib/mina/token/forest-iterator.unit-test.ts index 97f0409ca3..18c6966743 100644 --- a/src/lib/mina/token/forest-iterator.unit-test.ts +++ b/src/lib/mina/token/forest-iterator.unit-test.ts @@ -16,6 +16,7 @@ import { import assert from 'assert'; import { Field, Bool } from '../../provable/wrapped.js'; import { PublicKey } from '../../provable/crypto/signature.js'; +import { NetworkId } from '../../../mina-signer/index.js'; // RANDOM NUMBER GENERATORS for account updates @@ -56,7 +57,7 @@ test.custom({ timeBudget: 1000 })( (flatUpdatesBigint) => { // reference: bigint callforest hash from mina-signer let forestBigint = accountUpdatesToCallForest(flatUpdatesBigint); - let expectedHash = callForestHash(forestBigint, 'testnet'); + let expectedHash = callForestHash(forestBigint, 'devnet'); let flatUpdates = flatUpdatesBigint.map(accountUpdateFromBigint); let forest = AccountUpdateForest.fromFlatArray(flatUpdates); diff --git a/src/lib/provable/crypto/signature.ts b/src/lib/provable/crypto/signature.ts index d1f0cced8a..d5ed209d81 100644 --- a/src/lib/provable/crypto/signature.ts +++ b/src/lib/provable/crypto/signature.ts @@ -266,7 +266,7 @@ class Signature extends CircuitValue { let publicKey = PublicKey.fromPrivateKey(privKey).toGroup(); let d = privKey.s; - // we chose an arbitrary prefix for the signature, and it happened to be 'testnet' + // we chose an arbitrary prefix for the signature // there's no consequences in practice and the signatures can be used with any network // if there needs to be a custom nonce, include it in the message itself let kPrime = Scalar.from( @@ -274,14 +274,14 @@ class Signature extends CircuitValue { { fields: msg.map((f) => f.toBigInt()) }, { x: publicKey.x.toBigInt(), y: publicKey.y.toBigInt() }, d.toBigInt(), - 'testnet' + 'devnet' ) ); let { x: r, y: ry } = Group.generator.scale(kPrime); let k = ry.isOdd().toBoolean() ? kPrime.neg() : kPrime; let h = hashWithPrefix( - signaturePrefix('testnet'), + signaturePrefix('devnet'), msg.concat([publicKey.x, publicKey.y, r]) ); let e = Scalar.fromField(h); @@ -296,11 +296,11 @@ class Signature extends CircuitValue { verify(publicKey: PublicKey, msg: Field[]): Bool { let point = publicKey.toGroup(); - // we chose an arbitrary prefix for the signature, and it happened to be 'testnet' + // we chose an arbitrary prefix for the signature // there's no consequences in practice and the signatures can be used with any network // if there needs to be a custom nonce, include it in the message itself let h = hashWithPrefix( - signaturePrefix('testnet'), + signaturePrefix('devnet'), msg.concat([point.x, point.y, this.r]) ); diff --git a/src/mina-signer/src/signature.ts b/src/mina-signer/src/signature.ts index bd3d384978..64df48d994 100644 --- a/src/mina-signer/src/signature.ts +++ b/src/mina-signer/src/signature.ts @@ -44,7 +44,7 @@ export { }; const networkIdMainnet = 0x01n; -const networkIdTestnet = 0x00n; +const networkIdDevnet = 0x00n; type Signature = { r: Field; s: Scalar }; type SignatureJson = { field: string; scalar: string }; @@ -111,7 +111,7 @@ function verifyFieldElement( * @param privateKey The `privateKey` represents an element of the Pallas scalar field, and should be given as a native bigint. * It can be converted from the base58 string representation using {@link PrivateKey.fromBase58}. * - * @param networkId The `networkId` is either "testnet" or "mainnet" and ensures that testnet transactions can + * @param networkId The `networkId` is either "devnet"/"testnet" or "mainnet" and ensures that testnet transactions can * never be used as valid mainnet transactions. * * @see {@link deriveNonce} and {@link hashMessage} for details on how the nonce and hash are computed. @@ -331,8 +331,9 @@ function getNetworkIdHashInput(network: NetworkId): [bigint, number] { switch (s) { case 'mainnet': return [networkIdMainnet, 8]; + case 'devnet': case 'testnet': - return [networkIdTestnet, 8]; + return [networkIdDevnet, 8]; default: return networkIdOfString(s); } @@ -356,6 +357,7 @@ const signaturePrefix = (network: NetworkId) => { switch (s) { case 'mainnet': return prefixes.signatureMainnet; + case 'devnet': case 'testnet': return prefixes.signatureTestnet; default: @@ -368,6 +370,7 @@ const zkAppBodyPrefix = (network: NetworkId) => { switch (s) { case 'mainnet': return prefixes.zkappBodyMainnet; + case 'devnet': case 'testnet': return prefixes.zkappBodyTestnet; default: diff --git a/src/mina-signer/src/signature.unit-test.ts b/src/mina-signer/src/signature.unit-test.ts index 0565a1b9af..64dc027cf1 100644 --- a/src/mina-signer/src/signature.unit-test.ts +++ b/src/mina-signer/src/signature.unit-test.ts @@ -56,16 +56,21 @@ function checkConsistentSingle( // check that various multi-field hash inputs can be verified function checkCanVerify(msg: HashInput, key: PrivateKey, pk: PublicKey) { + let sigDev = sign(msg, key, 'devnet'); let sigTest = sign(msg, key, 'testnet'); let sigMain = sign(msg, key, 'mainnet'); // verify - let okTestnetTestnet = verify(sigTest, msg, pk, 'testnet'); - let okMainnetTestnet = verify(sigMain, msg, pk, 'testnet'); - let okTestnetMainnet = verify(sigTest, msg, pk, 'mainnet'); + let okTestnetDevnet = verify(sigTest, msg, pk, 'devnet'); + let okDevnetTestnet = verify(sigDev, msg, pk, 'testnet'); + let okDevnetDevnet = verify(sigDev, msg, pk, 'devnet'); + let okMainnetDevnet = verify(sigMain, msg, pk, 'devnet'); + let okDevnetMainnet = verify(sigDev, msg, pk, 'mainnet'); let okMainnetMainnet = verify(sigMain, msg, pk, 'mainnet'); - expect(okTestnetTestnet).toEqual(true); - expect(okMainnetTestnet).toEqual(false); - expect(okTestnetMainnet).toEqual(false); + expect(okTestnetDevnet).toEqual(true); + expect(okDevnetTestnet).toEqual(true); + expect(okDevnetDevnet).toEqual(true); + expect(okMainnetDevnet).toEqual(false); + expect(okDevnetMainnet).toEqual(false); expect(okMainnetMainnet).toEqual(true); } From 28ea4f9a55a3e9cab12a209ca40973f03c81f0a7 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:59:01 -0700 Subject: [PATCH 03/11] replace hardcoded instances of testnet with devnet in signing code, constants being generated for the signatures are unchanged --- src/mina-signer/mina-signer.ts | 4 +- src/mina-signer/src/random-transaction.ts | 2 +- src/mina-signer/src/sign-legacy.unit-test.ts | 12 +++- .../src/sign-zkapp-command.unit-test.ts | 16 ++++++ src/mina-signer/src/signature.unit-test.ts | 8 +++ .../src/test-vectors/legacySignatures.ts | 56 +++++++++++++++++++ 6 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/mina-signer/mina-signer.ts b/src/mina-signer/mina-signer.ts index d6b9793a43..29d53757e0 100644 --- a/src/mina-signer/mina-signer.ts +++ b/src/mina-signer/mina-signer.ts @@ -152,7 +152,7 @@ class Client { */ signFields(fields: bigint[], privateKey: Json.PrivateKey): Signed { let privateKey_ = PrivateKey.fromBase58(privateKey); - let signature = sign({ fields }, privateKey_, 'testnet'); + let signature = sign({ fields }, privateKey_, 'devnet'); return { signature: Signature.toBase58(signature), publicKey: PublicKey.toBase58(PrivateKey.toPublicKey(privateKey_)), @@ -172,7 +172,7 @@ class Client { Signature.fromBase58(signature), { fields: data }, PublicKey.fromBase58(publicKey), - 'testnet' + 'devnet' ); } diff --git a/src/mina-signer/src/random-transaction.ts b/src/mina-signer/src/random-transaction.ts index ac475348e5..87d286fd28 100644 --- a/src/mina-signer/src/random-transaction.ts +++ b/src/mina-signer/src/random-transaction.ts @@ -141,7 +141,7 @@ const RandomTransaction = { zkappCommand, zkappCommandAndFeePayerKey, zkappCommandJson, - networkId: Random.oneOf('testnet', 'mainnet', { + networkId: Random.oneOf('testnet', 'mainnet', 'devnet', { custom: 'other', }), accountUpdateWithCallDepth: accountUpdate, diff --git a/src/mina-signer/src/sign-legacy.unit-test.ts b/src/mina-signer/src/sign-legacy.unit-test.ts index 3654943682..2a54a56cf2 100644 --- a/src/mina-signer/src/sign-legacy.unit-test.ts +++ b/src/mina-signer/src/sign-legacy.unit-test.ts @@ -23,7 +23,7 @@ import { RandomTransaction } from './random-transaction.js'; import { NetworkId } from './types.js'; let { privateKey, publicKey } = keypair; -let networks: NetworkId[] = ['testnet', 'mainnet']; +let networks: NetworkId[] = ['devnet', 'testnet', 'mainnet']; // test hard-coded cases against reference signature @@ -73,16 +73,26 @@ test( verifyPayment(payment, sig, publicKey, network); // valid signatures & verification matrix + let devnet = signPayment(payment, privateKey, 'devnet'); let testnet = signPayment(payment, privateKey, 'testnet'); let mainnet = signPayment(payment, privateKey, 'mainnet'); + assert(verify(devnet, 'testnet') === true); + assert(verify(testnet, 'devnet') === true); + assert(verify(testnet, 'testnet') === true); assert(verify(testnet, 'mainnet') === false); assert(verify(mainnet, 'testnet') === false); + + assert(verify(devnet, 'devnet') === true); + assert(verify(devnet, 'mainnet') === false); + assert(verify(mainnet, 'devnet') === false); assert(verify(mainnet, 'mainnet') === true); // fails when signing with wrong private key let testnetWrong = signPayment(payment, otherKey, 'testnet'); + let devnetWrong = signPayment(payment, otherKey, 'devnet'); let mainnetWrong = signPayment(payment, otherKey, 'mainnet'); + assert(verify(devnetWrong, 'devnet') === false); assert(verify(testnetWrong, 'testnet') === false); assert(verify(mainnetWrong, 'mainnet') === false); } diff --git a/src/mina-signer/src/sign-zkapp-command.unit-test.ts b/src/mina-signer/src/sign-zkapp-command.unit-test.ts index e0f1ccacdc..d833a6b5da 100644 --- a/src/mina-signer/src/sign-zkapp-command.unit-test.ts +++ b/src/mina-signer/src/sign-zkapp-command.unit-test.ts @@ -112,6 +112,12 @@ test( expect(hash).toEqual(hashSnarky.toBigInt()); // check against different network hash + expect(hash).not.toEqual( + accountUpdateHash( + accountUpdate, + NetworkId.toString(networkId) === 'mainnet' ? 'devnet' : 'mainnet' + ) + ); expect(hash).not.toEqual( accountUpdateHash( accountUpdate, @@ -262,6 +268,9 @@ test( expect( verify(sigFieldElements, networkId === 'mainnet' ? 'testnet' : 'mainnet') ).toEqual(false); + expect( + verify(sigFieldElements, networkId === 'mainnet' ? 'devnet' : 'mainnet') + ).toEqual(false); // full end-to-end test: sign a zkapp transaction let sig = signZkappCommand(zkappCommandJson, feePayerKeyBase58, networkId); @@ -278,6 +287,13 @@ test( networkId === 'mainnet' ? 'testnet' : 'mainnet' ) ).toEqual(false); + expect( + verifyZkappCommandSignature( + sig, + feePayerAddressBase58, + networkId === 'mainnet' ? 'devnet' : 'mainnet' + ) + ).toEqual(false); } ); diff --git a/src/mina-signer/src/signature.unit-test.ts b/src/mina-signer/src/signature.unit-test.ts index 64dc027cf1..98055fea85 100644 --- a/src/mina-signer/src/signature.unit-test.ts +++ b/src/mina-signer/src/signature.unit-test.ts @@ -42,6 +42,14 @@ function checkConsistentSingle( networkId === 'mainnet' ? 'testnet' : 'mainnet' ) ).toEqual(false); + expect( + verifyFieldElement( + sig, + msg, + pk, + networkId === 'mainnet' ? 'devnet' : 'mainnet' + ) + ).toEqual(false); // consistent with OCaml let msgMl = FieldConst.fromBigint(msg); diff --git a/src/mina-signer/src/test-vectors/legacySignatures.ts b/src/mina-signer/src/test-vectors/legacySignatures.ts index 7090587475..db17f153e9 100644 --- a/src/mina-signer/src/test-vectors/legacySignatures.ts +++ b/src/mina-signer/src/test-vectors/legacySignatures.ts @@ -91,6 +91,62 @@ let strings = [ * - the 3 strings. */ let signatures: { [k: string]: { field: string; scalar: string }[] } = { + devnet: [ + { + field: + '3925887987173883783388058255268083382298769764463609405200521482763932632383', + scalar: + '445615701481226398197189554290689546503290167815530435382795701939759548136', + }, + { + field: + '11838925242791061185900891854974280922359055483441419242429642295065318643984', + scalar: + '5057044820006008308046028014628135487302791372585541488835641418654652928805', + }, + { + field: + '13570419670106759824217358880396743605262660069048455950202130815805728575057', + scalar: + '2256128221267944805514947515637443480133552241968312777663034361688965989223', + }, + { + field: + '18603328765572408555868399359399411973012220541556204196884026585115374044583', + scalar: + '17076342019359061119005549736934690084415105419939473687106079907606137611470', + }, + { + field: + '1786373894608285187089973929748850875336413409295396991315429715474432640801', + scalar: + '10435258496141097615588833319454104720521911644724923418749752896069542389757', + }, + { + field: + '11710586766419351067338319607483640291676872446372400739329190129174446858072', + scalar: + '21663533922934564101122062377096487451020504743791218020915919810997397884837', + }, + { + field: + '11583775536286847540414661987230057163492736306749717851628536966882998258109', + scalar: + '14787360096063782022566783796923142259879388947509616216546009448340181956495', + }, + { + field: + '24809097509137086694730479515383937245108109696879845335879579016397403384488', + scalar: + '23723859937408726087117568974923795978435877847592289069941156359435022279156', + }, + { + field: + '23803497755408154859878117448681790665144834176143832235351783889976460433296', + scalar: + '21219917886278462345652813021708727397787183083051040637716760620250038837684', + }, + ], testnet: [ { field: From 53abba62067898155c086795e3b3e8e40deb7f38 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:35:13 -0700 Subject: [PATCH 04/11] update mina-signer tests to include devnet client --- src/mina-signer/tests/client.test.ts | 7 ++- src/mina-signer/tests/message.test.ts | 71 ++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/mina-signer/tests/client.test.ts b/src/mina-signer/tests/client.test.ts index 4ca384a2d2..e620429ee2 100644 --- a/src/mina-signer/tests/client.test.ts +++ b/src/mina-signer/tests/client.test.ts @@ -13,7 +13,12 @@ describe('Client Class Initialization', () => { expect(client).toBeDefined(); }); - it('should throw an error if a value that is not `mainnet` or `testnet` is specified', () => { + it('should accept `devnet` as a valid network parameter', () => { + client = new Client({ network: 'devnet' }); + expect(client).toBeDefined(); + }); + + it('should throw an error if a value that is not `mainnet`, `devnet`, or `testnet` is specified', () => { try { //@ts-ignore client = new Client({ network: 'new-network' }); diff --git a/src/mina-signer/tests/message.test.ts b/src/mina-signer/tests/message.test.ts index bd9586fb19..451972f1b5 100644 --- a/src/mina-signer/tests/message.test.ts +++ b/src/mina-signer/tests/message.test.ts @@ -37,6 +37,14 @@ describe('Message', () => { expect(client.verifyTransaction(message)).toEqual(true); }); + it('does not verify a signed message from `devnet`', () => { + const message = client.signMessage('hello', privateKey); + const devnetClient = new Client({ network: 'devnet' }); + const invalidMessage = devnetClient.verifyMessage(message); + expect(invalidMessage).toBeFalsy(); + expect(devnetClient.verifyTransaction(message)).toEqual(false); + }); + it('does not verify a signed message from `testnet`', () => { const message = client.signMessage('hello', privateKey); const testnetClient = new Client({ network: 'testnet' }); @@ -46,12 +54,12 @@ describe('Message', () => { }); }); - describe('Testnet network', () => { + describe('Devnet network', () => { let client: Client; let privateKey: PrivateKey; beforeAll(async () => { - client = new Client({ network: 'testnet' }); + client = new Client({ network: 'devnet' }); ({ privateKey } = client.genKeys()); }); @@ -89,4 +97,63 @@ describe('Message', () => { expect(mainnetClient.verifyTransaction(message)).toEqual(false); }); }); + + describe('Testnet network', () => { + let testnetClient: Client; + let devnetClient: Client; + let privateKey: PrivateKey; + + beforeAll(async () => { + testnetClient = new Client({ network: 'testnet' }); + devnetClient = new Client({ network: 'devnet' }); + ({ privateKey } = devnetClient.genKeys()); + }); + + it('generates the same signatures as devnet', () => { + const testnetMessage = testnetClient.signMessage('hello', privateKey); + const devnetMessage = devnetClient.signMessage('hello', privateKey); + expect(testnetMessage).toEqual(devnetMessage); + }); + + + it('generates the same signatures as devnet using signTransaction', () => { + const testnetMessage = testnetClient.signTransaction('hello', privateKey); + const devnetMessage = devnetClient.signTransaction('hello', privateKey); + expect(testnetMessage).toEqual(devnetMessage); + }); + + it('verifies a signed message from devnet and vice versa', () => { + const testnetMessage = testnetClient.signMessage('hello', privateKey); + const devnetMessage = devnetClient.signMessage('hello', privateKey); + + const verifiedDevnetMessage = testnetClient.verifyMessage(devnetMessage); + const verifiedTestnetMessage = devnetClient.verifyMessage(testnetMessage); + expect(verifiedDevnetMessage).toBeTruthy(); + expect(verifiedTestnetMessage).toBeTruthy(); + + expect(testnetClient.verifyTransaction(devnetMessage)).toEqual(true); + expect(devnetClient.verifyTransaction(testnetMessage)).toEqual(true); + }); + + it('verifies a signed message generated by signTransaction from devnet and vice versa', () => { + const testnetMessage = testnetClient.signTransaction('hello', privateKey); + const devnetMessage = devnetClient.signTransaction('hello', privateKey); + + const verifiedDevnetMessage = testnetClient.verifyMessage(devnetMessage); + const verifiedTestnetMessage = devnetClient.verifyMessage(testnetMessage); + expect(verifiedDevnetMessage).toBeTruthy(); + expect(verifiedTestnetMessage).toBeTruthy(); + + expect(testnetClient.verifyTransaction(devnetMessage)).toEqual(true); + expect(devnetClient.verifyTransaction(testnetMessage)).toEqual(true); + }); + + it('does not verify a signed message from `mainnet`', () => { + const message = testnetClient.signMessage('hello', privateKey); + const mainnetClient = new Client({ network: 'mainnet' }); + const invalidMessage = mainnetClient.verifyMessage(message); + expect(invalidMessage).toBeFalsy(); + expect(mainnetClient.verifyTransaction(message)).toEqual(false); + }); + }); }); From ddb1d66c0fc8c85a53eb8794b8ba400d98cea0c8 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:54:06 -0700 Subject: [PATCH 05/11] add tests for devnet mina-signer --- src/mina-signer/src/signature.unit-test.ts | 4 +- src/mina-signer/tests/message.test.ts | 2 +- src/mina-signer/tests/payment.test.ts | 208 +++++++++++++++++- .../tests/stake-delegation.test.ts | 130 ++++++++++- src/mina-signer/tests/zkapp.unit-test.ts | 2 +- 5 files changed, 340 insertions(+), 6 deletions(-) diff --git a/src/mina-signer/src/signature.unit-test.ts b/src/mina-signer/src/signature.unit-test.ts index 98055fea85..3bd81efcd3 100644 --- a/src/mina-signer/src/signature.unit-test.ts +++ b/src/mina-signer/src/signature.unit-test.ts @@ -33,7 +33,7 @@ function checkConsistentSingle( // verify expect(verifyFieldElement(sig, msg, pk, networkId)).toEqual(true); - // verify against different network + // if the signature was generated with networkId=mainnet, the signature should not verify against testnet or devnet expect( verifyFieldElement( sig, @@ -118,6 +118,7 @@ for (let i = 0; i < 10; i++) { // hard coded single field elements let hardcoded = [0n, 1n, 2n, p - 1n]; for (let x of hardcoded) { + checkConsistentSingle(x, key, keySnarky, publicKey, 'devnet'); checkConsistentSingle(x, key, keySnarky, publicKey, 'testnet'); checkConsistentSingle(x, key, keySnarky, publicKey, 'mainnet'); checkConsistentSingle(x, key, keySnarky, publicKey, { custom: 'other' }); @@ -125,6 +126,7 @@ for (let i = 0; i < 10; i++) { // random single field elements for (let i = 0; i < 10; i++) { let x = randomFields[i]; + checkConsistentSingle(x, key, keySnarky, publicKey, 'devnet'); checkConsistentSingle(x, key, keySnarky, publicKey, 'testnet'); checkConsistentSingle(x, key, keySnarky, publicKey, 'mainnet'); checkConsistentSingle(x, key, keySnarky, publicKey, { custom: 'other' }); diff --git a/src/mina-signer/tests/message.test.ts b/src/mina-signer/tests/message.test.ts index 451972f1b5..0b5b6f6fd2 100644 --- a/src/mina-signer/tests/message.test.ts +++ b/src/mina-signer/tests/message.test.ts @@ -134,7 +134,7 @@ describe('Message', () => { expect(testnetClient.verifyTransaction(devnetMessage)).toEqual(true); expect(devnetClient.verifyTransaction(testnetMessage)).toEqual(true); }); - + it('verifies a signed message generated by signTransaction from devnet and vice versa', () => { const testnetMessage = testnetClient.signTransaction('hello', privateKey); const devnetMessage = devnetClient.signTransaction('hello', privateKey); diff --git a/src/mina-signer/tests/payment.test.ts b/src/mina-signer/tests/payment.test.ts index de84939d67..34fbf24abe 100644 --- a/src/mina-signer/tests/payment.test.ts +++ b/src/mina-signer/tests/payment.test.ts @@ -103,6 +103,23 @@ describe('Payment', () => { expect(hashedPayment).toBeDefined(); }); + it('does not verify a signed payment from `devnet`', () => { + const payment = client.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetClient = new Client({ network: 'devnet' }); + const invalidPayment = devnetClient.verifyPayment(payment); + expect(invalidPayment).toBeFalsy(); + expect(devnetClient.verifyTransaction(payment)).toEqual(false); + }); + it('does not verify a signed payment from `testnet`', () => { const payment = client.signPayment( { @@ -121,12 +138,12 @@ describe('Payment', () => { }); }); - describe('Testnet network', () => { + describe('Devnet network', () => { let client: Client; let keypair: Keypair; beforeAll(async () => { - client = new Client({ network: 'testnet' }); + client = new Client({ network: 'devnet' }); keypair = client.genKeys(); }); @@ -239,4 +256,191 @@ describe('Payment', () => { expect(mainnetClient.verifyTransaction(payment)).toEqual(false); }); }); + describe('Testnet network', () => { + let testnetClient: Client; + let devnetClient: Client; + let keypair: Keypair; + + beforeAll(async () => { + testnetClient = new Client({ network: 'testnet' }); + devnetClient = new Client({ network: 'devnet' }); + keypair = testnetClient.genKeys(); + }); + + it('generates the same signed payment as devnet', () => { + const testnetPayment = testnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetPayment = devnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + expect(testnetPayment).toEqual(devnetPayment); + }); + + it('generates the same signed transaction by using signTransaction as a devnet client', () => { + const testnetTransaction = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetTransaction = devnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + expect(testnetTransaction).toEqual(devnetTransaction); + }); + + it('devnet client verifies a signed testnet payment and vice versa', () => { + const testnetPayment = testnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetPayment = devnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const verifiedDevnetPayment = testnetClient.verifyPayment(devnetPayment); + expect(verifiedDevnetPayment).toBeTruthy(); + expect(testnetClient.verifyTransaction(devnetPayment)).toEqual(true); + + const verifiedTestnetPayment = devnetClient.verifyPayment(testnetPayment); + expect(verifiedTestnetPayment).toBeTruthy(); + expect(devnetClient.verifyTransaction(testnetPayment)).toEqual(true); + }); + it('devnet client verifies a signed testnet payment generated with signTransaction and vice versa', () => { + const testnetPayment = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetPayment = devnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const verifiedDevnetPayment = testnetClient.verifyPayment(devnetPayment); + expect(verifiedDevnetPayment).toBeTruthy(); + expect(testnetClient.verifyTransaction(devnetPayment)).toEqual(true); + + const verifiedTestnetPayment = devnetClient.verifyPayment(testnetPayment); + expect(verifiedTestnetPayment).toBeTruthy(); + expect(devnetClient.verifyTransaction(testnetPayment)).toEqual(true); + }); + + it('generates same signed payment hash as devnet', () => { + const testnetPayment = testnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const hashedTestnetPayment = testnetClient.hashPayment(testnetPayment); + const devnetPayment = devnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const hashedDevnetPayment = devnetClient.hashPayment(devnetPayment); + expect(hashedTestnetPayment).toEqual(hashedDevnetPayment); + }); + + it('generates same signed payment hash as devnet for payment generated with signTransaction', () => { + const testnetPayment = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const hashedTestnetPayment = testnetClient.hashPayment(testnetPayment); + const devnetPayment = devnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const hashedDevnetPayment = devnetClient.hashPayment(devnetPayment); + expect(hashedTestnetPayment).toEqual(hashedDevnetPayment); + }); + + it('does not verify a signed payment from `mainnet`', () => { + const payment = testnetClient.signPayment( + { + to: keypair.publicKey, + from: keypair.publicKey, + amount: '1', + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const mainnetClient = new Client({ network: 'mainnet' }); + const invalidPayment = mainnetClient.verifyPayment(payment); + expect(invalidPayment).toBeFalsy(); + expect(mainnetClient.verifyTransaction(payment)).toEqual(false); + }); + }); }); diff --git a/src/mina-signer/tests/stake-delegation.test.ts b/src/mina-signer/tests/stake-delegation.test.ts index 16cdf0d8f6..58d273040c 100644 --- a/src/mina-signer/tests/stake-delegation.test.ts +++ b/src/mina-signer/tests/stake-delegation.test.ts @@ -114,7 +114,7 @@ describe('Stake Delegation', () => { }); }); - describe('Testnet network', () => { + describe('Devnet network', () => { let client: Client; let keypair: Keypair; @@ -211,4 +211,132 @@ describe('Stake Delegation', () => { expect(mainnetClient.verifyTransaction(delegation)).toEqual(false); }); }); + describe('Testnet network', () => { + let testnetClient: Client; + let devnetClient: Client; + let keypair: Keypair; + + beforeAll(async () => { + testnetClient = new Client({ network: 'testnet' }); + devnetClient = new Client({ network: 'devnet' }); + keypair = testnetClient.genKeys(); + }); + + it('generates the same signed stake delegation as devnet', () => { + const testnetDelegation = testnetClient.signStakeDelegation( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetDelegation = testnetClient.signStakeDelegation( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + expect(testnetDelegation).toEqual(devnetDelegation); + }); + it('generates the same signed stake delegation as devnet using signTransaction', () => { + const testnetDelegation = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetDelegation = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + expect(testnetDelegation).toEqual(devnetDelegation); + }); + + + it('verifies a signed delegation from devnet and vice versa', () => { + const testnetDelegation = testnetClient.signStakeDelegation( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetDelegation = testnetClient.signStakeDelegation( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const verifiedDevnetDelegation = testnetClient.verifyStakeDelegation(devnetDelegation); + expect(verifiedDevnetDelegation).toBeTruthy(); + expect(testnetClient.verifyTransaction(devnetDelegation)).toEqual(true); + + const verifiedTestnetDelegation = devnetClient.verifyStakeDelegation(testnetDelegation); + expect(verifiedTestnetDelegation).toBeTruthy(); + expect(devnetClient.verifyTransaction(testnetDelegation)).toEqual(true); + }); + + + it('verifies a signed delegation generated by signTransaction from devnet and vice versa', () => { + const testnetDelegation = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const devnetDelegation = testnetClient.signTransaction( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const verifiedDevnetDelegation = testnetClient.verifyStakeDelegation(devnetDelegation); + expect(verifiedDevnetDelegation).toBeTruthy(); + expect(testnetClient.verifyTransaction(devnetDelegation)).toEqual(true); + + const verifiedTestnetDelegation = devnetClient.verifyStakeDelegation(testnetDelegation); + expect(verifiedTestnetDelegation).toBeTruthy(); + expect(devnetClient.verifyTransaction(testnetDelegation)).toEqual(true); + }); + + it('does not verify a signed message from `mainnet`', () => { + const delegation = testnetClient.signStakeDelegation( + { + to: keypair.publicKey, + from: keypair.publicKey, + fee: '1', + nonce: '0', + }, + keypair.privateKey + ); + const mainnetClient = new Client({ network: 'mainnet' }); + const invalidMessage = mainnetClient.verifyStakeDelegation(delegation); + expect(invalidMessage).toBeFalsy(); + expect(mainnetClient.verifyTransaction(delegation)).toEqual(false); + }); + }); }); diff --git a/src/mina-signer/tests/zkapp.unit-test.ts b/src/mina-signer/tests/zkapp.unit-test.ts index 1b3ffb66c3..6580df4a8c 100644 --- a/src/mina-signer/tests/zkapp.unit-test.ts +++ b/src/mina-signer/tests/zkapp.unit-test.ts @@ -8,7 +8,7 @@ import { PrivateKey } from '../../lib/provable/crypto/signature.js'; import { Signature } from '../src/signature.js'; import { mocks } from '../../bindings/crypto/constants.js'; -const client = new Client({ network: 'testnet' }); +const client = new Client({ network: 'devnet' }); let { publicKey, privateKey } = client.genKeys(); let dummy = ZkappCommand.toJSON(ZkappCommand.empty()); From fa811ab3560c907e73b2f7eca025644c85e9114e Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:05:52 -0700 Subject: [PATCH 06/11] update bindings to accept devnet as string network id --- CHANGELOG.md | 1 + generate-keys.js | 2 +- src/bindings | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f895921488..83e2ee810c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Compiling stuck in the browser for recursive zkprograms https://github.com/o1-labs/o1js/pull/1906 - Error message in `rangeCheck16` gadget https://github.com/o1-labs/o1js/pull/1920 +- Deprecate `testnet` `networkId` in favor of `devnet` https://github.com/o1-labs/o1js/pull/1938 ## [2.1.0](https://github.com/o1-labs/o1js/compare/b04520d...e1bac02) - 2024-11-13 diff --git a/generate-keys.js b/generate-keys.js index b702948882..b638d116a7 100755 --- a/generate-keys.js +++ b/generate-keys.js @@ -1,6 +1,6 @@ #!/usr/bin/env node import Client from './dist/node/mina-signer/mina-signer.js'; -let client = new Client({ network: 'testnet' }); +let client = new Client({ network: 'devnet' }); console.log(client.genKeys()); diff --git a/src/bindings b/src/bindings index 2c62a9a755..317c73252b 160000 --- a/src/bindings +++ b/src/bindings @@ -1 +1 @@ -Subproject commit 2c62a9a755f1b128f89cc2131814df7157f68109 +Subproject commit 317c73252b85702570ca95e85943cf749727074c From 4b926eaee1ad706550d7c064209dd34ce51a4072 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:17:58 -0700 Subject: [PATCH 07/11] remove testnet from comment --- src/mina-signer/src/signature.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mina-signer/src/signature.ts b/src/mina-signer/src/signature.ts index 64df48d994..784927e4ca 100644 --- a/src/mina-signer/src/signature.ts +++ b/src/mina-signer/src/signature.ts @@ -111,7 +111,7 @@ function verifyFieldElement( * @param privateKey The `privateKey` represents an element of the Pallas scalar field, and should be given as a native bigint. * It can be converted from the base58 string representation using {@link PrivateKey.fromBase58}. * - * @param networkId The `networkId` is either "devnet"/"testnet" or "mainnet" and ensures that testnet transactions can + * @param networkId The `networkId` is either "devnet" or "mainnet" and ensures that testnet transactions can * never be used as valid mainnet transactions. * * @see {@link deriveNonce} and {@link hashMessage} for details on how the nonce and hash are computed. From 79f1fd18f93d9c9643b89f89cbc91211583ae50f Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Sun, 15 Dec 2024 19:35:26 -0700 Subject: [PATCH 08/11] rebuild bindings --- src/bindings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings b/src/bindings index 317c73252b..0c908a2c1d 160000 --- a/src/bindings +++ b/src/bindings @@ -1 +1 @@ -Subproject commit 317c73252b85702570ca95e85943cf749727074c +Subproject commit 0c908a2c1dd2c9c444a2f65aaf52dcdcc616a4b5 From 92dd1a34df1381e31ba1a094125c9f6225a6ddf4 Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Sun, 15 Dec 2024 19:53:39 -0700 Subject: [PATCH 09/11] remove duplicate test vectors in mina signer --- src/mina-signer/src/sign-legacy.unit-test.ts | 4 +- .../src/test-vectors/legacySignatures.ts | 56 ------------------- 2 files changed, 3 insertions(+), 57 deletions(-) diff --git a/src/mina-signer/src/sign-legacy.unit-test.ts b/src/mina-signer/src/sign-legacy.unit-test.ts index 2a54a56cf2..30cf195743 100644 --- a/src/mina-signer/src/sign-legacy.unit-test.ts +++ b/src/mina-signer/src/sign-legacy.unit-test.ts @@ -29,7 +29,9 @@ let networks: NetworkId[] = ['devnet', 'testnet', 'mainnet']; for (let network of networks) { let i = 0; - let reference = signatures[NetworkId.toString(network)]; + let reference = NetworkId.toString(network) === 'testnet' + ? signatures['devnet'] + : signatures[NetworkId.toString(network)]; for (let payment of payments) { let signature = signPayment(payment, privateKey, network); diff --git a/src/mina-signer/src/test-vectors/legacySignatures.ts b/src/mina-signer/src/test-vectors/legacySignatures.ts index db17f153e9..7cb559ce6d 100644 --- a/src/mina-signer/src/test-vectors/legacySignatures.ts +++ b/src/mina-signer/src/test-vectors/legacySignatures.ts @@ -147,62 +147,6 @@ let signatures: { [k: string]: { field: string; scalar: string }[] } = { '21219917886278462345652813021708727397787183083051040637716760620250038837684', }, ], - testnet: [ - { - field: - '3925887987173883783388058255268083382298769764463609405200521482763932632383', - scalar: - '445615701481226398197189554290689546503290167815530435382795701939759548136', - }, - { - field: - '11838925242791061185900891854974280922359055483441419242429642295065318643984', - scalar: - '5057044820006008308046028014628135487302791372585541488835641418654652928805', - }, - { - field: - '13570419670106759824217358880396743605262660069048455950202130815805728575057', - scalar: - '2256128221267944805514947515637443480133552241968312777663034361688965989223', - }, - { - field: - '18603328765572408555868399359399411973012220541556204196884026585115374044583', - scalar: - '17076342019359061119005549736934690084415105419939473687106079907606137611470', - }, - { - field: - '1786373894608285187089973929748850875336413409295396991315429715474432640801', - scalar: - '10435258496141097615588833319454104720521911644724923418749752896069542389757', - }, - { - field: - '11710586766419351067338319607483640291676872446372400739329190129174446858072', - scalar: - '21663533922934564101122062377096487451020504743791218020915919810997397884837', - }, - { - field: - '11583775536286847540414661987230057163492736306749717851628536966882998258109', - scalar: - '14787360096063782022566783796923142259879388947509616216546009448340181956495', - }, - { - field: - '24809097509137086694730479515383937245108109696879845335879579016397403384488', - scalar: - '23723859937408726087117568974923795978435877847592289069941156359435022279156', - }, - { - field: - '23803497755408154859878117448681790665144834176143832235351783889976460433296', - scalar: - '21219917886278462345652813021708727397787183083051040637716760620250038837684', - }, - ], mainnet: [ { field: From 3fdc3f1f42f0a838e832338f40194b40dc13981d Mon Sep 17 00:00:00 2001 From: querolita Date: Wed, 18 Dec 2024 13:36:34 +0100 Subject: [PATCH 10/11] update bindings without the huge diff --- src/bindings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings b/src/bindings index 317c73252b..e3a31e1e9c 160000 --- a/src/bindings +++ b/src/bindings @@ -1 +1 @@ -Subproject commit 317c73252b85702570ca95e85943cf749727074c +Subproject commit e3a31e1e9cb136aae2509b4cfd1a03f84c1d443e From f9ab3ab1ffc0828f675d108ed2dbad23a10818eb Mon Sep 17 00:00:00 2001 From: hattyhattington17 <181872047+hattyhattington17@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:28:08 -0700 Subject: [PATCH 11/11] apply bindings ci patch --- src/bindings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings b/src/bindings index 120fb8d547..14ce3b8f5e 160000 --- a/src/bindings +++ b/src/bindings @@ -1 +1 @@ -Subproject commit 120fb8d54725c4b96bfb7847ddfaf6dfb9344cf7 +Subproject commit 14ce3b8f5e23dbcd9afe3d53304ee84cfc92076b