From fbd888aa6e87dbed91903e373ae2d664a6ef6ec4 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 13 May 2026 16:30:10 +0900 Subject: [PATCH] Update GRIDS --- GRIDS.md | 525 +++++++++++++++++++++++++++---------------------------- 1 file changed, 254 insertions(+), 271 deletions(-) diff --git a/GRIDS.md b/GRIDS.md index e560452..e6b5099 100644 --- a/GRIDS.md +++ b/GRIDS.md @@ -1,271 +1,254 @@ - -# GRIDS: Gajumaru Remote Instruction Dispatch System v1 - -- **Document Created**: 2025-01-17 -- **Document Last Modified**: 2025-12-08 -- **Document Author**: Craig Everett `` -- **Document Version**: 3 (For Implementation) -- **Wiki Page Created**: 2026-05-02 -- **Wiki Page Last Modified**: 2026-05-02 -- **Wiki Page Author**: Peter Harpending `` -- **Notes**: Copied from random PDF I (PRH) found on my computer written by - Craig, dated 2025-01-17. - -The GRIDS protocol defines methods for encoding three basic actions within the -Gajumaru ecosystem: - -1. A method for encoding "spend" transactions in a URL where the host section - indicates a specific endpoint node to use, the required network ID being - then queried from the endpoint. -2. A method for encoding "transfer" transactions in a URL where the host - section indicates a network to use but leaves resolving an endpoint node up - to the client. -3. A method for performing digital "dead drop" signatures, queuing signature - requests on a server, retrieving them with a client, and returning the - resulting signed output to the server. - - -## The Problem - -In computing there is a strong tradeoff between usability and security. In the -cryptocurrency world this is compounded by the inherent complexity of the -systems involved. This has resulted in a common pattern of developers coding -wallet features directly into the local execution environments of the -applications they wish to integrate with a cryptocurrency system (typically a -blockchain). - -For example, it is common for games based around on-chain tokens to integrate -wallet features directly into the game client itself. This prevents the user -from having to leave the game, open another application (their wallet), sign a -transaction, and then return to the game. - -As another example, it is overwhelmingly common for developers to write -wallets as browser plugins that interact directly with in-page applications -running in the same browser. - -In both cases the incentives for bad actors to compromise the execution -environment itself in order to capture private key data or seed phrases is -overwhelming. Separation of signature and app execution context is needed. -Separating the execution context requires a way for apps requesting signatures -and apps capable of providing signatures to communicate not only across -execution environments on a single system, but also across completely separate -systems. - -GRIDS defines a way to to combine communication of limited, known transaction -types (such as simple spends) with a way to convey arbitrarily complex -transaction data that may require out-of-band communication with a signature -client. - -## The Schema - -The GRIDS schema is very similar to HTTP/HTTPS, and even translates directly -to an HTTP request URL in the case of a dead-drop instruction. - -The basic schema is: - -``` -[grid(s)]://[host]/[version]/[instruction]/[path](?a=[amount]&p=[payload]) -``` - -Where: - -- The schema identifier is either `grids` or `grid`. If the instruction is a - dead-drop signature then the schema may be `grid` to indicate that the - initial pick up request must be made over HTTP rather than HTTPS. If the - instruction is not a dead-drop, then there is no difference between the two. -- The `host` element is interpreted differently based on instruction type: - - For `s` (short for "spend") it is the network ID where the spend is to - take place. - - For `t` (short for "transfer") it is a `host:port` location of a node - where the client can retrieve the network ID. - - For `d` (short for "dead-drop") it is a `host:port` location of a service - where a message to be signed is awaiting pickup. -- The `version` element is the protocol version. -- As mentioned above, the `instruction` element is one of `s` (for "spend"), - `t` (for "transfer"—same as spend but with different host semantics) or `d` - (for "dead-drop"). -- In the case of dead-drops, the `path` element is the HTTP path to the pickup - location. In the case of spends/transfers it is the address of the party to - be paid, with (optional) amount and payload details packed into query args - of the forms - - - `a=[amount]` denominated in pucks, represented in the numerals `[0-9]` - - `p=[payload]` represented as URL-encoded binary data - -## The simple case: SpendTX - -Spends are simple on-chain transactions that transfer coins (Gajus/Pucks) from -one account to another. - -Defined as a record, the inner data in a SpendTX looks like this: - -```erlang --record(spend_tx, - {sender_id :: string(), - recipient_id :: string(), - amount :: non_neg_integer(), - gas_price :: pos_integer(), - gas :: pos_integer(), - ttl :: pos_integer(), - nonce :: pos_integer(), - payload :: binary()}). -``` - -All elements are required with the exception of the `payload`, which can be -empty. The payload is used to tag spend transactions with meaningful data such -as text indicating what a transaction was for or an invoice number useful for -tracking within an accounting system. Elements such as the `gas_price`, `gas`, -`ttl` and `nonce` are all elements that a client wallet is expected to -populate on its own. - -The external data required for a SpendTX is the network ID of the specific -chain that the spend transaction is intended for. The network ID is part of -the external encoding of the TX, the encoded representation of the transaction -(including the network ID) is what the client ultimately signs. The -combination of the nonce and network ID prevents TXs from being replayed on -the same network or replayed across different networks. - -The information required from a party requesting an on-chain payment is -therefore reduced to: - -1. The account to be paid -2. The amount -3. Any payload desired (an invoice number, for example) -4. The network ID or a host address of a node from which the network ID can be - obtained. - -This data is encoded in a GRIDS URL as noted above. - -GRIDS URLs should be provided to users as both plain text and a QR code to -make it easy to verify their content as well as make it possible to easily use -both desktop (copy-paste) and mobile (camera input) wallet apps. - -### Example Spends - -Let's say a point-of-sale system at shop needs to charge a customer 25 Gajus. -The POS system knows its own account address for the register, knows the -invoice number, knows the amount to charge, and knows that it is operating on -the `groot.mainnet` network, but does not know the -customer's account number. - -Assume the following payment information: - -- Store account: `ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U` -- Amount: 25 Gajus -- Invoice number: `20250117-0001` - -The POS system can generate a GRIDS request encoded as: - -``` -grids://groot.mainnet/1/s/ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U?a=25000000000000000000&p=20250117-0001 -``` - -Alternately, if the POS system is operating on an associate chain that isn't as -common, or is running its own backend node for efficiency purposes, it could -request a "transfer" instruction, specifying its -node's public address and the wallet can retrieve the network ID from there: - -``` -grids://some.shop:4321/1/t/ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U?a=25000000000000000000&p=20250117-0001 -``` - -If the node running at `some.shop:4321` is a part of `groot.mainnet`, then -these two request URLs are effectively identical. - -## Dead-Drops - -The most flexible case for GRIDS is the dead-drop. Using this technique -anything can be communicated to a client, signed, and returned. Dead-drops can -be used for signatures of contract calls, login messages, or any other kind of -message signature one might require. - -As mentioned above, dead-drop GRIDS URLs are converted to HTTP URLs by -stripping off the GRIDS version and instruction tags and reassembling the -request as an HTTP or HTTPS request. - -For example: - -``` -grids://foo.com/1/d/some_random_path -> https://foo.com/some_random_path -grid://foo.com/1/d/some_random_path -> http://foo.com/some_random_path -``` - -After that conversion takes place, the client makes a GET request to the HTTP -URL indicated. The response from the server is a JSON object containing the -unsigned data and some metadata that tells the client what kind of message is -being signed so that the client can select the correct signature method. - -After signing, the JSON object is updated with the signed data and the public -half of the signing key. The client then submits in a POST request the updated -JSON object back to the original endpoint from which the unsigned data was -retrieved. - -### Signature Request Messages (initial GET) - -The response to the initial GET request takes the form of a JSON object with this shape: - -```json -{"grids" : 1, - "chain" : "gajumaru", - "network_id" : "groot.mainnet", - "type" : "tx", - "public_id" : "ak_2SLsxkPavd1oDwUgCyZkMoQJJvMkUWymg1BEK7egx5rVU8xanV", - "payload" : "Any data here"} -``` - -- The `"grids"` version will always match the version encoded in the request URL. -- The `"chain"` element exists in case other projects want to adopt the GRIDS - protocol, in which case the protocol rules of the specific chain family will - dictate things like serialization details. -- The `"network_id"` is necessary for the client (and end-user) to verify that - activity is occurring where expected and binds the resulting signature to - that specific network. -- The `"type"` may be `"message"`, `"tx"` or `"ack"`. A `"message"` signature - is used either for verifiable messages or login schemes. An `"ack"` is an - optional response to a `"tx"` or `"message"` response POST. -- The `"public_id"` can either be a public key (on-chain account) or the - **boolean** `false` (note absence of quotes). - - - If the `public_id` is `false`, then it is up to the client to pick a key to - use (and then populate this field). - - If an ID is specified, then the client should select that account or fail if it is not available. - -- The `"payload"` is the data to be signed. In the case of a - `"tx"` request (a contract call, for example), this data - will be transaction data encoded according to the Gajumaru - protocol's rules. Any Gajumaru signature routine will - understand how to interpret and handle this data. In the - case of a `"message"` request, this will typically be a - simple string in plain text that the client interprets as a - binary string, appends the prefix (Erlang binary notation) - `<<"Gajumaru Signed Message:\n">>`, and then signs. - Prefixing message request payloads with this string prevents - attackers from disguising transaction signature requests as - text message signatures. - -### Signed Data Messages (subsequent POST) - -After the client signs the payload, it will populate the -`"public_id"` element (if it was `false` previously) and add -`"signature"` element with the requested signature. The -resulting object that must be POSTed back to the origin is -therefore: - -```json -{"grids" : 1, - "chain" : "gajumaru", - "network_id" : "groot.mainnet", - "type" : "tx", - "public_id" : "ak_2SLsxkPavd1oDwUgCyZkMoQJJvMkUWymg1BEK7egx5rVU8xanV", - "payload" : "Any data here", - "signature" : "XiuCkEOHINkQN83QUxmIAfmiiRN2XflktnNMtdZDzgW0TQK/YQaurQjfL3R5eoXJvCuUZRgPpKfCvtsXbphDCQ=="} -``` - -The server (or any other observer of this message) now has -enough information to establish for certain whether whoever -signed this message has control of the private key that -corresponds to the public key indicated in the message. - -Signing of randomized and timestamped messages can be used to -implement First-Party Single Sign-On (1pSSO) schemes without -any requirement that the server side maintain private data. +# GRIDS: Gajumaru Remote Instruction Dispatch System v1 + +- **Document Created**: 2025-01-17 +- **Document Last Modified**: 2025-12-08 +- **Document Author**: Craig Everett `` +- **Document Version**: 3 (For Implementation) +- **Wiki Page Created**: 2026-05-02 +- **Wiki Page Last Modified**: 2026-05-02 +- **Wiki Page Author**: Peter Harpending `` +- **Notes**: Copied from random PDF I (PRH) found on my computer written by + Craig, dated 2025-01-17. + +The GRIDS protocol defines methods for encoding three basic actions within the +Gajumaru ecosystem: + +1. A method for encoding "spend" transactions in a URL where the host section + indicates a specific endpoint node to use, the required network ID being + then queried from the endpoint. +2. A method for encoding "transfer" transactions in a URL where the host + section indicates a network to use but leaves resolving an endpoint node up + to the client. +3. A method for performing digital "dead drop" signatures, queuing signature + requests on a server, retrieving them with a client, and returning the + resulting signed output to the server. + + +## The Problem + +In computing there is a strong tradeoff between usability and security. +In the cryptocurrency world this is compounded by the inherent complexity of the systems involved. +This has resulted in a common pattern of developers coding wallet features directly into the local execution environments of the applications they wish to integrate with a cryptocurrency system (typically a blockchain). + +For example, it is common for games based around on-chain tokens to integrate wallet features directly into the game client itself. +This prevents the user from having to leave the game, open another application (their wallet), sign a transaction, and then return to the game. + +As another example, it is overwhelmingly common for developers to write wallets as browser plugins that interact directly with in-page applications running in the same browser. + +In both cases the incentives for bad actors to compromise the execution environment itself in order to capture private key data or seed phrases is overwhelming. +Separation of signature and app execution context is needed. +Separating the execution context requires a way for apps requesting signatures and apps capable of providing signatures to communicate not only across execution environments on a single system, but also across completely separate systems. + +GRIDS defines a way to to combine communication of limited, known transaction types (such as simple spends) with a way to convey arbitrarily complex transaction data that may require out-of-band communication with a signature client. + +## The Schema + +The GRIDS schema is very similar to HTTP/HTTPS, and even translates directly to an HTTP request URL in the case of a dead-drop instruction. + +The basic schema is: + +``` +[grid(s)]://[host]/[version]/[instruction]/[path](?a=[amount]&p=[payload]) +``` + +Where: + +- The schema identifier is either `grids` or `grid`. If the instruction is a + dead-drop signature then the schema may be `grid` to indicate that the + initial pick up request must be made over HTTP rather than HTTPS. If the + instruction is not a dead-drop, then there is no difference between the two. +- The `host` element is interpreted differently based on instruction type: + - For `s` (short for "spend") it is the network ID where the spend is to + take place. + - For `t` (short for "transfer") it is a `host:port` location of a node + where the client can retrieve the network ID. + - For `d` (short for "dead-drop") it is a `host:port` location of a service + where a message to be signed is awaiting pickup. +- The `version` element is the protocol version. +- As mentioned above, the `instruction` element is one of `s` (for "spend"), + `t` (for "transfer"—same as spend but with different host semantics) or `d` + (for "dead-drop"). +- In the case of dead-drops, the `path` element is the HTTP path to the pickup + location. In the case of spends/transfers it is the address of the party to + be paid, with (optional) amount and payload details packed into query args + of the forms + + - `a=[amount]` denominated in pucks, represented in the numerals `[0-9]` + - `p=[payload]` represented as URL-encoded binary data + +## The simple case: SpendTX + +Spends are simple on-chain transactions that transfer coins (Gajus/Pucks) from +one account to another. + +Defined as a record, the inner data in a SpendTX looks like this: + +```erlang +-record(spend_tx, + {sender_id :: string(), + recipient_id :: string(), + amount :: non_neg_integer(), + gas_price :: pos_integer(), + gas :: pos_integer(), + ttl :: pos_integer(), + nonce :: pos_integer(), + payload :: binary()}). +``` + +All elements are required with the exception of the `payload`, which can be +empty. The payload is used to tag spend transactions with meaningful data such +as text indicating what a transaction was for or an invoice number useful for +tracking within an accounting system. Elements such as the `gas_price`, `gas`, +`ttl` and `nonce` are all elements that a client wallet is expected to +populate on its own. + +The external data required for a SpendTX is the network ID of the specific +chain that the spend transaction is intended for. The network ID is part of +the external encoding of the TX, the encoded representation of the transaction +(including the network ID) is what the client ultimately signs. The +combination of the nonce and network ID prevents TXs from being replayed on +the same network or replayed across different networks. + +The information required from a party requesting an on-chain payment is +therefore reduced to: + +1. The account to be paid +2. The amount +3. Any payload desired (an invoice number, for example) +4. The network ID or a host address of a node from which the network ID can be + obtained. + +This data is encoded in a GRIDS URL as noted above. + +GRIDS URLs should be provided to users as both plain text and a QR code to +make it easy to verify their content as well as make it possible to easily use +both desktop (copy-paste) and mobile (camera input) wallet apps. + +### Example Spends + +Let's say a point-of-sale system at shop needs to charge a customer 25 Gajus. +The POS system knows its own account address for the register, knows the +invoice number, knows the amount to charge, and knows that it is operating on +the `groot.mainnet` network, but does not know the +customer's account number. + +Assume the following payment information: + +- Store account: `ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U` +- Amount: 25 Gajus +- Invoice number: `20250117-0001` + +The POS system can generate a GRIDS request encoded as: + +``` +grids://groot.mainnet/1/s/ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U?a=25000000000000000000&p=20250117-0001 +``` + +Alternately, if the POS system is operating on an associate chain that isn't as +common, or is running its own backend node for efficiency purposes, it could +request a "transfer" instruction, specifying its +node's public address and the wallet can retrieve the network ID from there: + +``` +grids://some.shop:4321/1/t/ak_srFAGY9Dq6p8LVoPSQ8o86s6EFAqWsXHKLDvpzPFcZ8txtR6U?a=25000000000000000000&p=20250117-0001 +``` + +If the node running at `some.shop:4321` is a part of `groot.mainnet`, then +these two request URLs are effectively identical. + +## Dead-Drops + +The most flexible case for GRIDS is the dead-drop. Using this technique +anything can be communicated to a client, signed, and returned. Dead-drops can +be used for signatures of contract calls, login messages, or any other kind of +message signature one might require. + +As mentioned above, dead-drop GRIDS URLs are converted to HTTP URLs by +stripping off the GRIDS version and instruction tags and reassembling the +request as an HTTP or HTTPS request. + +For example: + +``` +grids://foo.com/1/d/some_random_path -> https://foo.com/some_random_path +grid://foo.com/1/d/some_random_path -> http://foo.com/some_random_path +``` + +After that conversion takes place, the client makes a GET request to the HTTP +URL indicated. The response from the server is a JSON object containing the +unsigned data and some metadata that tells the client what kind of message is +being signed so that the client can select the correct signature method. + +After signing, the JSON object is updated with the signed data and the public +half of the signing key. The client then submits in a POST request the updated +JSON object back to the original endpoint from which the unsigned data was +retrieved. + +### Signature Request Messages (initial GET) + +The response to the initial GET request takes the form of a JSON object with this shape: + +```json +{"grids" : 1, + "chain" : "gajumaru", + "network_id" : "groot.mainnet", + "type" : "tx", + "public_id" : "ak_2SLsxkPavd1oDwUgCyZkMoQJJvMkUWymg1BEK7egx5rVU8xanV", + "payload" : "Any data here"} +``` + +- The `"grids"` version will always match the version encoded in the request URL. +- The `"chain"` element exists in case other projects want to adopt the GRIDS + protocol, in which case the protocol rules of the specific chain family will + dictate things like serialization details. +- The `"network_id"` is necessary for the client (and end-user) to verify that + activity is occurring where expected and binds the resulting signature to + that specific network. +- The `"type"` may be `"message"`, `"binary"`, `"tx"` or `"ack"`. + - A `"message"` signature is a UTF-8 string used either for verifiable messages or login schemes. + - A `"binary"` signature is the same as a `"message"` signature, but is performed over binary data encoded as base64. + - A `"tx"` is a request for signature of a transaction (usually call data or contract deployment). + - An `"ack"` is an optional response to a `"tx"` or `"message"` response POST. +- The `"public_id"` can either be a public key (on-chain account) or the **boolean** `false` (note absence of quotes). + - If the `public_id` is `false`, then it is up to the client to pick a key to + use (and then populate this field). + - If an ID is specified, then the client should select that account or fail if it is not available. +- The `"payload"` is the data to be signed. In the case of a + `"tx"` request (a contract call, for example), this data + will be transaction data encoded according to the Gajumaru + protocol's rules. Any Gajumaru signature routine will + understand how to interpret and handle this data. In the + case of a `"message"` request, this will typically be a + simple string in plain text that the client interprets as a + binary string, prepends the binary string (Erlang binary notation) + `<<"Gajumaru Signed Message:\n">>`, and then signs. + Prefixing message request payloads with this string prevents + attackers from disguising transaction signature requests as + text message signatures. + +### Signed Data Messages (subsequent POST) + +After the client signs the payload, it will populate the +`"public_id"` element (if it was `false` previously) and add +`"signature"` element with the requested signature. The +resulting object that must be POSTed back to the origin is +therefore: + +```json +{"grids" : 1, + "chain" : "gajumaru", + "network_id" : "groot.mainnet", + "type" : "tx", + "public_id" : "ak_2SLsxkPavd1oDwUgCyZkMoQJJvMkUWymg1BEK7egx5rVU8xanV", + "payload" : "Any data here", + "signature" : "XiuCkEOHINkQN83QUxmIAfmiiRN2XflktnNMtdZDzgW0TQK/YQaurQjfL3R5eoXJvCuUZRgPpKfCvtsXbphDCQ=="} +``` + +The server (or any other observer of this message) now has +enough information to establish for certain whether whoever +signed this message has control of the private key that +corresponds to the public key indicated in the message. + +Signing of randomized and timestamped messages can be used to +implement First-Party Single Sign-On (1pSSO) schemes without +any requirement that the server side maintain private data.