The Padge Protocol is an innovative, persistent storage protocol designed to provide a decentralized platform for various platforms and users to upload and permanently store their personal achievement data. This protocol not only ensures the durability of data but also facilitates the verification of data authenticity, ensuring security and reliability.
The Padge Protocol, which is built on top of [[did-core]] , is an innovative, persistent storage protocol designed to provide a decentralized platform for various platforms and users to upload and permanently store their personal achievement data. This protocol not only ensures the durability of data but also facilitates the verification of data authenticity, ensuring security and reliability.
This Protocol, along with its comprehensive implementation via the Padge Network, offers a sophisticated and secure framework for the permanent preservation and verification of personal achievements. This system ensures a secure, transparent, and user-friendly platform for individuals to manage and showcase their personal achievements, thereby enriching their digital identities and underscoring their accomplishments.
Padge Document is at the heart of the Padge Protocol network and facilitates the circulation of data within the system. It consists of the following main components:
This segment offers a clear and detailed understanding of the achievement, allowing any viewer to fully appreciate its nature and worth.
The Collector represents the owner of the achievement, containing:
The Validator is essentially a collection of public keys used to validate the authenticity and integrity of a padge document. Any legitimate padge document signed by the Validator's public key can be permanently stored on decentralized storage platforms such as Arweave and IPFS. This step is crucial for maintaining the trust and security of the data as it confirms that the data has not been tampered with and is officially endorsed by the issuing entity.
With the collector's consent, Platform utilize their DID and public key to assemble user data into a json document with platform's signature
Collector then can retrieve and verify the json documents from the platform, using their own DID and public key to sign and confirm the ownership of document.
When a document is signed by both the platform and the collector, it can be submitted to the Validator for verification. The Validator will check whether the signatures of the document are valid and confirm the ownership of signatures. If the document passes the verification, the Validator will sign the document with its own public key and store it on decentralized storage platforms.
The data is now permanently stored and available for future verification. Any third party can verify the validity and authenticity of the data using the information embedded within the the document. This verification process ensures that the data remains unchanged and secure, while also protecting the privacy and security of the data owner.
did:
, a method identifier, and a unique,
method-specific identifier specified by the DID method.
did:bit:satoshi.bit
It also could be present with query
did:bit:satoshi.bit#/?block_num=12924745
{
"creator": {
"id": "clva4rggk000109l35uq7859e",
"name": "did team",
"extensions": []
},
"padge": {
"id": "clvz2f8jj00020al3ewewexk2",
"name": "Padge Protocol",
"desc": "Awarded to individuals who have demonstrated expertise in the implementation and innovation of the Padge protocol.",
"media": {
"url": "https://asset.padge.com/badges/clvz2dspb00010al32a8c1oih.png",
"mimeType": "image/png",
"hash": "22dfbc521c1b1da9786a8bb917198ab03238299388b1b927c70d53a2b6379137"
},
"extensions": []
},
"platform": {
"did": "did:bit:padge.bit",
"name": "Padge Platform",
"extensions": []
},
"collector": {
"did": "did:bit:padge.bit"
},
"salt": "5df7927f90158736",
"version": "1",
"proofs": [
{
"id": "0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
"msg": [
"ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410",
"2024-05-01T11:10:46.172Z"
],
"role": "platform",
"sig": "0x38dbbc793d9ee341bdc8c6dc645ca25961a93523c2b1af19a6d347edc83ecab05b6193b66951f6fabf69e9cc61f03f7a5f70f1ccd289940d210a71f4b3d376f61b",
"verification_method": {
"did": "did:bit:promer94.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x4b0c01Ea6919d20BC24b1f829f18Bd077C246d34"
}
},
{
"id": "02edbc48-0477-43ab-a64b-5fcd5656d65f",
"msg": [
"ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410",
"2024-05-02T11:10:46.172Z"
],
"role": "collector",
"sig": "0x5a19303e5c8ad6a8105b86c2f5dfea5e318c69cdae9eca6eed9f96b55823fb995cd7a97c7181485157b030bdc87b463cd242ad242aca3cbb9fa5454e56bac64b1c",
"verification_method": {
"did": "did:bit:simonxu.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x89a54d9eec390ea6a97fd2249a5921fc367f867b"
}
},
{
"id": "b5f22498-4c0a-462d-8e63-9a5f7f688799",
"role": "validator",
"msg": [
"0x38dbbc793d9ee341bdc8c6dc645ca25961a93523c2b1af19a6d347edc83ecab05b6193b66951f6fabf69e9cc61f03f7a5f70f1ccd289940d210a71f4b3d376f61b",
"0x5a19303e5c8ad6a8105b86c2f5dfea5e318c69cdae9eca6eed9f96b55823fb995cd7a97c7181485157b030bdc87b463cd242ad242aca3cbb9fa5454e56bac64b1c",
"2024-05-03T11:10:46.172Z"
],
"sig": "0xd2937c4ce301fcacca50e15a55cd60d0ecde32c81e7b72e682c8a0d9f8e785e41044bfd6ab453e68d5317301cd075dc2c125e7c0b6140ebe5d6299bbc348088b1c",
"prev_sig": [
"0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
"02edbc48-0477-43ab-a64b-5fcd5656d65f"
],
"verification_method": {
"did": "did:bit:singer.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x87CDBd91293A221a108A4c70547436e7bf240C1A"
}
}
]
}
The Padge Protocol data model is based on the [=Padge Document=], which consists of the following content:
The Padge represents metadata descriptions of achievements, providing a comprehensive record that includes, but is not limited to:
{
"namespace": "common",
"total_supply":"",
"start_time":"",
"end_time":"",
"criteria":""
}
Creator represents the entity creates the achievement. It stores the following fields:
{
"namespace": "common",
"bio":"",
"links":[{name: '', value: ''}]
}
Platform represents the entity that issues the platform. It stores the following fields:
{
"namespace": "common",
"padge": {
"awarded_time": "",
"awarded_rank": ""
}
}
Collector represents the entity that collects achievements. It stores the following fields:
The version of the current Padge Document. It is used for future compatibility. It MUST be a [[JSON]] string.
The salt is a random string that is used to prevent replay attacks. It MUST be a [[JSON]] string.
The proofs are the cryptographic proofs that validate the authenticity of the document. It MUST be a [[JSON]] array. The items in the array MUST be [[JSON]] objects.
Platform MUST transform its data into a padge document which is adhere to the Data Model with empty [=proofs=] parts.
{
"creator": {
"id": "clva4rggk000109l35uq7859e",
"name": "did team",
"extensions": []
},
"padge": {
"id": "clvz2f8jj00020al3ewewexk2",
"name": "Padge Protocol",
"desc": "Awarded to individuals who have demonstrated expertise in the implementation and innovation of the Padge protocol.",
"media": {
"url": "https://asset.padge.com/badges/clvz2dspb00010al32a8c1oih.png",
"mimeType": "image/png",
"hash": "22dfbc521c1b1da9786a8bb917198ab03238299388b1b927c70d53a2b6379137"
},
extensions: []
},
"platform": {
"did": "did:bit:padge.bit",
"name": "Padge Platform",
"extensions": []
},
"collector": {
"did": "did:bit:padge.bit"
},
"salt": "5df7927f90158736",
"version": "1",
proofs: []
}
The previous padge document MUST be stringified deterministic by alphabetic order of keys and hashed by SHA256 with salt.
import stringify from 'json-stable-stringify'
async function digestMessage(message: string, salt: string) {
const data = new TextEncoder().encode(`${message}${salt}`);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}
const padgeDocs = {
"creator": {
"id": "clva4rggk000109l35uq7859e",
"name": "did team",
"extensions": []
},
"padge": {
"id": "clvz2f8jj00020al3ewewexk2",
"name": "Padge Protocol",
"desc": "Awarded to individuals who have demonstrated expertise in the implementation and innovation of the Padge protocol.",
"media": {
"url": "https://asset.padge.com/badges/clvz2dspb00010al32a8c1oih.png",
"mimeType": "image/png",
"hash": "22dfbc521c1b1da9786a8bb917198ab03238299388b1b927c70d53a2b6379137"
},
extensions: []
},
"platform": {
"did": "did:bit:padge.bit",
"name": "Padge Platform",
"extensions": []
},
"collector": {
"did": "did:bit:padge.bit"
},
"salt": "5df7927f90158736",
"version": "1",
"proofs": []
}
async function calculateHash() {
const hash = await digestMessage(stringify(padgeDocs), padgeDocs.salt)
return hash
}
calculateHash().then(console.log)
// hash: ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410
Platform MUST sign the hash of the padge document with its private key and and add its proof to the [=proofs=] part. The [=msg=] part MUST include the hash of current padge document and the timestamp.
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount('0xxxx')
const pendingPlatformProof = {
"id": "0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
"role": "platform",
"msg": [
// hash of padge document
'ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410',
// timestamp
'2024-05-01T11:10:46.172Z'
],
"sig": '',
"verification_method": {
"did": "did:bit:promer94.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x4b0c01Ea6919d20BC24b1f829f18Bd077C246d34",
}
}
const generatorProof = async (pendingProof: {
msg: string[],
}) => {
const msg = pendingProof.msg.join(',')
const sig = await account.signMessage({ message: msg })
return {
...pendingProof,
sig
}
}
generatorProof(pendingPlatformProof).then(console.log)
/** platform proofs
{
"id":"0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
"msg":["ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410","2024-05-09T11:10:46.172Z"],
"role":"platform",
"sig":"0xa7b3ed166a5bb856d4c433c77c7af6306793f5bbcf8c5b2d544ea712b8d375001f6c8d005e77a4baf18d14edbc1af9dfab3c9baa93fae92a0164a17516194cb41b",
"verification_method":{
"did":"did:bit:promer94.bit#block_num=12924745",
"pubkey_type":"address",
"pubkey_value":"0x4b0c01Ea6919d20BC24b1f829f18Bd077C246d34"
}
}
*
/
Collector MUST sign the hash of the padge document with its private key and add its proof to the [=proofs=] part. The [=msg=] part MUST include the hash of current padge document and the timestamp.
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount('0xxxx')
const pendingCollectorProof = {
"id": "02edbc48-0477-43ab-a64b-5fcd5656d65f",
"role": "collector",
"msg": [
// hash of padge document
'ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410',
// timestamp
'2024-05-02T11:10:46.172Z'
],
"sig": '',
"verification_method": {
"did": "did:bit:simonxu.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x4b0c01Ea6919d20BC24b1f829f18Bd077C246d34",
}
}
const generatorProof = async (pendingProof: {
msg: string[],
}) => {
const msg = pendingProof.msg.join(',')
const sig = await account.signMessage({ message: msg })
return {
...pendingProof,
sig
}
}
generatorProof(pendingCollectorProof).then(console.log)
/** collector proof
{
"id":"02edbc48-0477-43ab-a64b-5fcd5656d65f",
"msg":["ac1c2e28ff35714c047bf1629af1a45f0777afaa9775eda6fc499efe9685e410","2024-05-02T11:10:46.172Z"],
"role":"collector",
"sig":"0x5a19303e5c8ad6a8105b86c2f5dfea5e318c69cdae9eca6eed9f96b55823fb995cd7a97c7181485157b030bdc87b463cd242ad242aca3cbb9fa5454e56bac64b1c",
"verification_method":{
"did":"did:bit:simonxu.bit#block_num=12924745",
"pubkey_type":"address",
"pubkey_value":"0x89a54d9eec390ea6a97fd2249a5921fc367f867b"
}
}
*/
Once the padge documents has the platform proof and collector proof. It could be uploaded to the validator for future processing
Validator MUST sign the combination of the platform proof, collector proof with its private key and add its proof to the [=proofs=] part. The [=msg=] part MUST include the signatures which are defined by the [=prev_sig=] part and the timestamp.
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount('0xx')
const pendingValidatorProof = {
"id": "b5f22498-4c0a-462d-8e63-9a5f7f688799",
"role": 'validator',
"msg": [
// the order of proofs is defined by the prev_sig
// the signature of platform proof
"0x38dbbc793d9ee341bdc8c6dc645ca25961a93523c2b1af19a6d347edc83ecab05b6193b66951f6fabf69e9cc61f03f7a5f70f1ccd289940d210a71f4b3d376f61b",
// the signature of collector proof
"0x5a19303e5c8ad6a8105b86c2f5dfea5e318c69cdae9eca6eed9f96b55823fb995cd7a97c7181485157b030bdc87b463cd242ad242aca3cbb9fa5454e56bac64b1c",
"2024-05-03T11:10:46.172Z"
],
"sig": "0xd2937c4ce301fcacca50e15a55cd60d0ecde32c81e7b72e682c8a0d9f8e785e41044bfd6ab453e68d5317301cd075dc2c125e7c0b6140ebe5d6299bbc348088b1c",
"verification_method": {
"id": "did:bit:singer.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x87CDBd91293A221a108A4c70547436e7bf240C1A"
},
"prev_sig": [
// The id of collector proof
"0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
// The id of platform proof
"02edbc48-0477-43ab-a64b-5fcd5656d65f"
]
}
const generatorProof = async (pendingProof: {
msg: string[],
}) => {
const msg = pendingProof.msg.join(',')
const sig = await account.signMessage({ message: msg })
return {
...pendingProof,
sig
}
}
generatorProof(pendingValidatorProof).then(console.log)
/**
{
"id": "b5f22498-4c0a-462d-8e63-9a5f7f688799",
"role": "validator",
"msg": [
"0x38dbbc793d9ee341bdc8c6dc645ca25961a93523c2b1af19a6d347edc83ecab05b6193b66951f6fabf69e9cc61f03f7a5f70f1ccd289940d210a71f4b3d376f61b",
"0x5a19303e5c8ad6a8105b86c2f5dfea5e318c69cdae9eca6eed9f96b55823fb995cd7a97c7181485157b030bdc87b463cd242ad242aca3cbb9fa5454e56bac64b1c",
"2024-05-03T11:10:46.172Z"
],
"sig": "0xd2937c4ce301fcacca50e15a55cd60d0ecde32c81e7b72e682c8a0d9f8e785e41044bfd6ab453e68d5317301cd075dc2c125e7c0b6140ebe5d6299bbc348088b1c",
"verification_method": {
"id": "did:bit:singer.bit#block_num=12924745",
"pubkey_type": "address",
"pubkey_value": "0x87CDBd91293A221a108A4c70547436e7bf240C1A"
},
"prev_sig": [
"0450dfd3-9b05-4fa7-bf78-aa8fc234217d",
"02edbc48-0477-43ab-a64b-5fcd5656d65f"
]
}
*/