Rust JSON标准化库serde_json_canonicalizer的使用,实现JSON数据的规范化解析与序列化

Rust JSON标准化库serde_json_canonicalizer的使用,实现JSON数据的规范化解析与序列化

Crates.io Workflow Status Maintenance

简介

serde_json_canonicalizer是一个与RFC 8785兼容的JSON规范化方案输出库,用于serde_json。

JSON规范化方案RFC-8785定义了一种JSON序列化方案,允许在依赖数据字节级重现的加密操作中使用JSON数据。它可以代替将序列化格式存储为BASE64编码字符串或类似的打包方式,使得在处理可以规范化后再输入加密函数的JSON格式数据时更加容易。

使用示例

use serde_json_canonicalizer::{to_string, to_vec};

#[derive(serde::Serialize)]
struct Data {
    c: isize,
    b: bool,
    a: String,
}

let data = Data { c: 120, b: false, a: "Hello!".to_string() };
let expected = r#"{"a":"Hello!","b":false,"c":120}"#;

// 序列化为字符串或字节,可替代serde_json
let json_string = to_string(&data).unwrap();
let json_bytes = to_vec(&data).unwrap();

assert_eq!(json_string, expected);
assert_eq!(json_bytes, expected.as_bytes());

完整示例代码

// 添加依赖到Cargo.toml
// serde_json_canonicalizer = "0.3.0"
// serde = { version = "1.0", features = ["derive"] }

use serde::{Serialize, Deserialize};
use serde_json_canonicalizer::{to_string, to_vec, from_str};

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct User {
    id: u32,
    username: String,
    email: String,
    is_active: bool,
}

fn main() {
    // 创建示例数据
    let user = User {
        id: 42,
        username: "john_doe".to_string(),
        email: "john@example.com".to_string(),
        is_active: true,
    };

    // 序列化为规范化JSON字符串
    let canonical_json = to_string(&user).unwrap();
    println!("Canonical JSON: {}", canonical_json);
    
    // 序列化为规范化JSON字节
    let canonical_bytes = to_vec(&user).unwrap();
    println!("Canonical Bytes: {:?}", canonical_bytes);
    
    // 反序列化
    let deserialized: User = from_str(&canonical_json).unwrap();
    println!("Deserialized: {:?}", deserialized);
    
    // 验证数据一致性
    assert_eq!(user, deserialized);
    
    // 验证规范化输出
    // 即使字段顺序不同,规范化输出也会保持一致
    let expected_json = r#"{"email":"john@example.com","id":42,"is_active":true,"username":"john_doe"}"#;
    assert_eq!(canonical_json, expected_json);
}

许可证

MIT许可证

与serde_jcs的比较

创建这个库是因为serde_jcs似乎已被放弃,且该仓库中的问题列出了一些与RFC不同的地方。这个库旨在100%兼容RFC,成为多语言环境中的合适实现。


1 回复

Rust JSON标准化库serde_json_canonicalizer使用指南

概述

serde_json_canonicalizer是一个Rust库,用于实现JSON数据的规范化(canonical)解析与序列化。它基于流行的serde_json库,添加了对JSON数据的规范化处理能力,确保相同的逻辑内容总是产生相同的字节序列输出。

主要特性

  • 将JSON数据转换为规范化的形式
  • 确保相同的JSON数据总是产生相同的字符串表示
  • 处理浮点数的规范化表示
  • 保持键的排序一致性
  • 无空格和换行的紧凑输出

安装

在Cargo.toml中添加依赖:

[dependencies]
serde_json_canonicalizer = "0.1"
serde = { version = "1.0", features = ["derive"] }

基本使用方法

规范化序列化

use serde_json_canonicalizer::to_vec;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    name: String,
    age: u32,
    hobbies: Vec<String>,
}

fn main() {
    let person = Person {
        name: "Alice".to_string(),
        age: 30,
        hobbies: vec!["reading".to_string(), "hiking".to_string()],
    };

    // 规范化序列化
    let canonical_json = to_vec(&person).unwrap();
    println!("{}", String::from_utf8_lossy(&canonical_json));
    // 输出: {"age":30,"hobbies":["reading","hiking"],"name":"Alice"}
}

规范化解析

use serde_json_canonicalizer::from_slice;

fn main() {
    let json_data = br#"{
        "name": "Bob",
        "age": 25,
        "active": true
    }"#;

    // 规范化解析
    let parsed: serde_json::Value = from_slice(json_data).unwrap();
    println!("{:?}", parsed);
    // 输出: Object({"active": Bool(true), "age": Number(25), "name": String("Bob")})
}

高级用法

自定义类型规范化

use serde_json_canonicalizer::{to_vec, from_slice};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Product {
    id: u64,
    name: String,
    price: f64,
    categories: Vec<String>,
}

fn main() {
    let product = Product {
        id: 12345,
        name: "Rust Programming Book".to_string(),
        price: 39.99,
        categories: vec!["Programming".to_string(), "Books".to_string()],
    };

    // 序列化为规范化JSON
    let json_data = to_vec(&product).unwrap();
    
    // 从规范化JSON解析回来
    let parsed_product: Product = from_slice(&json_data).unwrap();
    
    assert_eq!(product, parsed_product);
}

处理浮点数规范化

use serde_json_canonicalizer::to_string;

fn main() {
    let data = serde_json::json!({
        "float1": 3.141592653589793,
        "float2": 1.0,
        "float3": 2.0e10,
        "float4": -0.0
    });

    let canonical = to_string(&data).unwrap();
    println!("{}", canonical);
    // 输出: {"float1":3.141592653589793,"float2":1.0,"float3":2.0e10,"float4":-0.0}
}

完整示例

以下是一个完整的示例,展示如何使用serde_json_canonicalizer进行JSON数据的规范化处理和验证:

use serde::{Serialize, Deserialize};
use serde_json_canonicalizer::{to_vec, from_slice};

// 定义一个用户结构体
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
    id: u64,
    username: String,
    email: String,
    permissions: Vec<String>,
    is_active: bool,
}

fn main() {
    // 创建用户实例
    let user = User {
        id: 123456,
        username: "rustacean".to_string(),
        email: "rust@example.com".to_string(),
        permissions: vec!["read".to_string(), "write".to_string()],
        is_active: true,
    };

    // 1. 序列化为规范化JSON
    let canonical_json = to_vec(&user).unwrap();
    println!("规范化JSON输出:");
    println!("{}", String::from_utf8_lossy(&canonical_json));
    // 输出: {"email":"rust@example.com","id":123456,"is_active":true,"permissions":["read","write"],"username":"rustacean"}

    // 2. 重新解析规范化JSON
    let parsed_user: User = from_slice(&canonical_json).unwrap();
    println!("\n解析后的用户数据:");
    println!("{:?}", parsed_user);
    
    // 3. 验证数据一致性
    assert_eq!(user, parsed_user);
    println!("\n验证通过 - 原始数据与解析后数据完全一致");

    // 4. 处理不同格式的相同数据
    let messy_json = br#"{
        "username": "rustacean",
        "email": "rust@example.com",
        "id": 123456,
        "is_active": true,
        "permissions": [
            "read",
            "write"
        ]
    }"#;
    
    let parsed_from_messy: User = from_slice(messy_json).unwrap();
    let messy_canonical = to_vec(&parsed_from_messy).unwrap();
    
    println!("\n混乱JSON的规范化输出:");
    println!("{}", String::from_utf8_lossy(&messy_canonical));
    
    // 5. 验证不同格式但相同逻辑内容的JSON规范化后是否一致
    assert_eq!(canonical_json, messy_canonical);
    println!("验证通过 - 不同格式的相同数据规范化后结果一致");
}

使用场景

  1. 数字签名验证:确保JSON数据在传输过程中没有被篡改
  2. 数据一致性检查:比较两个JSON数据是否逻辑等价
  3. 区块链应用:需要确定性序列化的场景
  4. 数据库存储:确保相同数据产生相同的存储表示

注意事项

  • 规范化JSON会改变原始JSON的格式(如空格、键顺序等)
  • 浮点数会被统一表示为最简形式
  • 所有Unicode字符会被转义为\uXXXX形式
  • 时间戳和其他特殊格式需要预先处理

这个库特别适合需要严格JSON数据一致性的应用场景,如密码学签名、数据验证等。

回到顶部