# 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
}

```
