# MetaAccess

### **Introduction**

MetaAccess 用于为提供一个去中心化的授权功能，让链上的加密数据，按照特定规则授权查看。

### Spec

约定需要两个协议，AccessControl和AccessPass。

* AccessControl负责设置权限进行控制，在发布密文内容的同时也发布AccessControl上链。
* AccessPass负责构建付费和授权交易，用于授权展示明文内容

#### AccessControl

path: `/metaaccess/accesscontrol`

```json
{
	"publicContent": "public part of content",//公开部分内容
	"publicPins":["PINID-1", "PINID-2"],//公开部分文件
	"publicPath": "/protocols/simplepublicbuzz",
	"controlPins":["PINID1","PINID2"], //Array of PINs that will be in control of accessing
	"controlPath": "/protocols/simpleasseccbuzz",//The pins which is in this path will be in control of accessing
	"manDomain":"",//待定
	"manPubkey":"THE-PUBKEY-OF-MAN", //Pubkey of the MAN node providing custody decryption services.
	"creatorPubkey":"THE-PUBKEY-OF-CREATOR",//Pubkey of the creator
	"encryptedKey":"Use the ECDH Key to Decrypt it and use that decryptedkey to decrypt the content",
	"holdCheck":{//hold检查
		"type":"mrc20" //"chainCoin" or "mrc20", 
		"ticker":"mc" //the ticker of mrc20;if type = chainCoin then it will be ignored
		"amount":"1000"
	},
	"payCheck":{//pay检查
		"type":"chainCoin", //"chainCoin" or "mrc20"
		"ticker":"",
		"amount":"0.00001",
		"payTo":"address",
		"validPeriod": "4320", //blocks，4320 means 1 month
	},
}
```

#### AccessPass

path: `/metaaccess/accesspass`

```json
{
	"accessControlID":"the-pinid-of-accesscontrol-file"
}
```

### 流程

创作者：

1. 应用端请求MAN获取publicKey，此时MAN会针对该请求生成一对公私钥并保存，然后返回man-publicKey
2. 应用端对钱包请求ecdh操作，根据传的钱包路径和man-publicKey，生成协商密钥SP
3. 应用端生成随机AES密钥-P1
4. 应用端编辑文本或图片，选择公开部分和付费部分，设置付费模式
5. 使用密钥-P1对付费部分内容进行AES加密，即对整个payload进行加密，得到内容txRaw
6. 使用协商密钥SP对密钥-P1进行AES加密，得到encrypted-key，构建`accesscontrol` 的pin
7. 把内容pin和`accesscontrol` 的pin统一广播上链

购买者：

1. 应用端构建`accesspass` ，output中带有针对`accesscontrol`所指定的payment
2. MAN提供获取密文的接口，需要带钱包的头部签名信息，MAN验证签名信息，获取带签名地址的`accesspass`
3. MAN根据accessControlID查询对应的`accesscontrol` ，用man-privateKey与creator-publicKey生成协商密钥SP
4. MAN先判断`accesspass`是否符合`accesscontrol` ，符合进行下一步，不符合则返回空
5. 用协商密钥SP对encrypted-key解密，获取密钥-P1
6. MAN用密钥-P1解密对应的controlPins，返回明文内容

### ECDH 配置说明

为了确保客户端与服务器端在密钥交换过程中能够正常协作，双方在 **ECDH (Elliptic Curve Diffie-Hellman)** 密钥交换协议中需要统一以下配置参数：

* **椭圆曲线类型**
  * 使用的曲线：`NIST P-256`（即 `secp256r1`或`prime256v1`）。
  * `P-256` 是一种被广泛使用的椭圆曲线，兼具较好的安全性和效率。
* **公钥和私钥格式**
  * 私钥和公钥均以 **Hex 编码** 的字符串形式进行传输。
  * 公钥在传输前通过 `PublicKey().Bytes()` 转换为字节数组，再进行 Hex 编码；私钥同样通过 `Bytes()` 转换为字节数组再 Hex 编码。
* **密钥派生**
  * 双方各自生成公私钥对后，使用私钥和对方的公钥计算共享密钥。
  * 共享密钥在计算完成后可以直接用于对称加密的密钥材料。

#### 对称加密配置 (AES)

* **对称加密算法**
  * 使用 `AES-256-CFB` 模式作为对称加密算法。
  * `CFB (Cipher Feedback)` 模式支持流式加密和解密，适合在共享密钥环境下进行数据加密。
* **AES 密钥生成**
  * 采用 256 位（32 字节）的随机字节作为 AES 密钥，生成时通过 `rand.Read` 随机生成。
  * AES 密钥使用 Hex 编码存储和传输。
* **初始化向量 (IV)**
  * 每次加密操作生成新的 16 字节（AES 块大小）的随机初始化向量（IV）。
  * IV 放在密文的前面一起传输，解密时需要从密文中提取 IV。

Go代码示例：

```go
// 生成 ECDH 密钥对
func GenKeyPair() (privateKey string, publicKey string, e error) {
    curve := ecdh.P256()
    privKeyA, err := curve.GenerateKey(rand.Reader)
    if err != nil {
        return
    }
    privateKey = hex.EncodeToString(privKeyA.Bytes())
    publicKey = hex.EncodeToString(privKeyA.PublicKey().Bytes())
    return
}

// 密钥交换过程
func PerformECDH(privKeyA *ecdh.PrivateKey, pubKeyB *ecdh.PublicKey) ([]byte, error) {
    return privKeyA.ECDH(pubKeyB) // 生成共享密钥
}

// 生成 AES 密钥
func GenerateAESKey() (string, error) {
    key := make([]byte, 32) // AES-256 key
    _, err := rand.Read(key)
    if err != nil {
        return "", err
    }
    return hexEncode(key), nil
}

// AES 加密
func EncryptPayloadAES(key, payload []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    ciphertext := make([]byte, aes.BlockSize+len(payload))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, err
    }
    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], payload)
    return ciphertext, nil
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.metaid.io/zh/metaid-xie-yi-gui-fan/metaaccess.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
