对于不同的语言,是否有任何稳定的序列化方法?



在我的项目中,我们有一个API,许多客户端可能会向这个API发送事务。交易应签名。客户端可以用任何语言(C++,C#,python,go等(编写,具有任何CPU架构和字节序。

现在的问题是将我们的事务模型序列化为字节,以便能够签名然后发送它。


为此,我们的团队选择了protobuf v3.3.0(proto语法= proto3(。

我们想使用信封图案,它看起来像:

message SignedTransaction {
message Transaction {/* any data that should be signed */}
Transaction transaction = 1;
Signature signature = 2;
}

要签名,我们只需序列化内部对象事务:

Transaction tx = <...>;
std::string bytes = tx.SerializeAsString();
// and then sign bytes

protobuf现在的问题在于,对于不同的语言,它似乎不是确定性的。今天我们编写了简单的原型文件,其中包含很少的整数和字符串,填充了相同的数据,将其序列化为不同的语言并观察结果。

我们尝试了Javascript,C++,Java,Swift,结果发现除了C++之外的所有内容都产生相同的输出字符串:

JavaScript、Java、Swift 产生:08B90A10BA0A1A106C6F6C206B656B20636865627572656B

出品C++:8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B

C++parseFromString(str)能够反序列化其他语言的字符串,但反之则不然。

问题是:

  1. 为什么C++protobuf会产生不同的弦?
  2. 我们可以为我们的用例使用哪些库?

详:

// test.proto:
syntax = "proto3";
package api;
message Msg {
uint32 a = 1;
int32  b = 2;
string c = 3;
bytes  d = 4;
}
// test.cpp:
api::Msg msg;
msg.set_a(1337);
msg.set_b(1338);
msg.set_c("lol kek cheburek");
std::string str = msg.SerializeAsString();
// str = 8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B

事实证明,我打印十六进制的代码中有错误。 详情

简短的回答: Protobuf 是一种稳定的序列化方法,可用于所描述的用例。

什么是序列化

我认为protobuf与术语序列化混淆了。protobuf所做的是一种特殊的编码。这除了

我怀疑不设置b会导致问题。这意味着 b 的值未初始化。Java对象自动初始化为零,C ++对象不自动初始化,这意味着内容可能只是随机值。可能发生在b

Protobuf 不稳定,因为内存中的同一对象可以用不同的方式序列化。主要是因为当一个对象有多个字段时,这些字段可以按任意顺序序列化。

请参阅此处的文档: https://developers.google.com/protocol-buffers/docs/encoding#implications .

最新更新