JS实现rlp编码

366 阅读1分钟

RLP(Recursive Length Prefix,递归长度前缀) 是以太坊定义的一种编码算法,网上目前没有js版本的实现方法,这里根据原理简单实现一下,ps:代码未优化,写的比较粗糙,欢迎大家在评论区批评及提出优化方案。关于RLP的原理概述,网上有很多,这里不再描述。

首先写几个方法函数:

1. 数组内数字求和:
const sumArr = (arr: Array<number>) => {
    var s = 0;
    for (var i=0; i<arr.length; i++) {
        s += arr[i];
    }
    return s;
}
2. 字符串转ASCII数组
const charToCode = (inputChar: any) => {
    let result: Array<number> = []
    for(let i in inputChar) {
        result.push(inputChar.charCodeAt(i))
    }
    return result
}
3.bit数组计算字节数

const calByte = (arr: Array<number>) => {
    var result: Array<number> = []
    for(let i in arr) {
        result.push(Math.floor(arr[i]/256))
    }
    return result
}
准备5个测试数据:
const data1 = "a"
const data2 = "abc"
const data3 = "The length of this sentence is more than 55 bytes, I know it because I pre-designed it"
const data4 = ["abc", "def"]
const data5 = ["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]

rpl编码支持输入字符串或者字符串数组,因此将计算字符串的方法单独封装:

const charToRlp = (inputChar: any) => {
    const length = inputChar.length

    if(length === 1) {
        return inputChar.charCodeAt(0)
    }else if (length <= 55) {
        return [128 + length].concat(charToCode(inputChar))
    } else {
        return [184 + Math.floor(length/256), length].concat(charToCode(inputChar))
    }
}
在主函数中根据输入格式做不同的处理,这里的代码思路是先把字符串转化为ASCII数组,再与描述长度的header拼接(感觉这种实现方法不是最优解,有待提高):
const rlpCoding = (input: any) => {
    let length: Array<number> = [] //当输入为一个数组的时候,Length是数组中每个字符串的长度
    const inpType = typeof input
    let resultLis: Array<number> = []
    
    if (inpType === "string") {
        return charToRlp(input)
    } else {
        for(let i in input) {
            length.push(input[i].length)
            resultLis = resultLis.concat(charToRlp(input[i]))
        }
        if(sumArr(length) <= 55) {
            return [192 + resultLis.length].concat(resultLis)
        } else {
            return [248 + Math.floor((sumArr(calByte(length)) + resultLis.length)/256), sumArr(calByte(length)) + resultLis.length].concat(resultLis)
        }
    }
}
测试输出
console.log("result1:", rlpCoding(data1), "\n",
             "result2:", rlpCoding(data2), "\n",
             "result3:", rlpCoding(data3), "\n",
             "result4:", rlpCoding(data4), "\n",
             "result5:", rlpCoding(data5)
            )