Просмотр исходного кода

crypto/merklenode: Implement serialization with serde.

We already have serde as a dependency, and not doing it this way
makes it way too complex, instead we can just use bincode+serde to
serialize and deserialize our Merkle trees.
parazyd 4 лет назад
Родитель
Сommit
c817082969
4 измененных файлов с 65 добавлено и 3 удалено
  1. 1 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 26 0
      src/bin/tree.rs
  4. 37 3
      src/crypto/merkle_node.rs

+ 1 - 0
Cargo.lock

@@ -1339,6 +1339,7 @@ dependencies = [
  "async-trait",
  "async-tungstenite",
  "bdk",
+ "bincode",
  "bitcoin",
  "blake2b_simd 1.0.0",
  "bs58",

+ 1 - 0
Cargo.toml

@@ -38,6 +38,7 @@ sha2 = "0.9.8"
 ripemd160 = "0.9.1"
 
 # Encoding and parsing
+bincode = "1.3.3"
 bs58 = "0.4.0"
 bytes = "1.1.0"
 hex = "0.4.3"

+ 26 - 0
src/bin/tree.rs

@@ -0,0 +1,26 @@
+use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
+use pasta_curves::{arithmetic::Field, pallas};
+use rand::rngs::OsRng;
+
+use drk::{crypto::merkle_node::MerkleNode, Result};
+
+fn main() -> Result<()> {
+    let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
+
+    for i in 0..10 {
+        tree.append(&MerkleNode(pallas::Base::random(&mut OsRng)));
+        if i % 3 == 0 {
+            tree.witness();
+        }
+    }
+
+    let bytes = bincode::serialize(&tree).unwrap();
+    let tree2: BridgeTree<MerkleNode, 32> = bincode::deserialize(&bytes).unwrap();
+
+    let root1 = tree.root();
+    let root2 = tree2.root();
+
+    assert_eq!(root1, root2);
+
+    Ok(())
+}

+ 37 - 3
src/crypto/merkle_node.rs

@@ -3,8 +3,17 @@ use std::{io, iter};
 use halo2_gadgets::primitives::sinsemilla::HashDomain;
 use incrementalmerkletree::{Altitude, Hashable};
 use lazy_static::lazy_static;
-use pasta_curves::{arithmetic::FieldExt, group::ff::PrimeFieldBits, pallas};
-use subtle::ConstantTimeEq;
+use pasta_curves::{
+    arithmetic::FieldExt,
+    group::ff::{PrimeField, PrimeFieldBits},
+    pallas,
+};
+use serde::{
+    de::{Deserializer, Error},
+    ser::Serializer,
+    Deserialize, Serialize,
+};
+use subtle::{ConstantTimeEq, CtOption};
 
 use crate::{
     crypto::constants::{
@@ -29,9 +38,34 @@ lazy_static! {
     };
 }
 
-#[derive(Debug, Clone, std::cmp::Eq)]
+#[derive(Debug, Clone, Eq)]
 pub struct MerkleNode(pub pallas::Base);
 
+impl MerkleNode {
+    pub fn to_bytes(&self) -> [u8; 32] {
+        self.0.to_repr()
+    }
+
+    pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
+        pallas::Base::from_repr(*bytes).map(MerkleNode)
+    }
+}
+
+impl Serialize for MerkleNode {
+    fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
+        self.to_bytes().serialize(serializer)
+    }
+}
+
+impl<'de> Deserialize<'de> for MerkleNode {
+    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
+        let parsed = <[u8; 32]>::deserialize(deserializer)?;
+        <Option<_>>::from(Self::from_bytes(&parsed)).ok_or_else(|| {
+            Error::custom("Attempted to deserialize a non-canonical representation of a Pallas base field element")
+        })
+    }
+}
+
 impl std::cmp::PartialEq for MerkleNode {
     fn eq(&self, other: &Self) -> bool {
         self.0.ct_eq(&other.0).into()