Skip to main content

dory_pcs/backends/arkworks/
blake2b_transcript.rs

1//! Blake2b-based Fiat-Shamir transcript for Dory proofs
2
3#![allow(missing_docs)]
4#![allow(clippy::missing_errors_doc)]
5#![allow(clippy::missing_panics_doc)]
6
7use crate::primitives::arithmetic::{Group, PairingCurve};
8use crate::primitives::serialization::Compress;
9use crate::primitives::transcript::Transcript;
10use crate::primitives::DorySerialize;
11use ark_ff::{BigInteger, PrimeField};
12use ark_serialize::CanonicalSerialize;
13use blake2::Blake2b512;
14use digest::{Digest, Output};
15use std::marker::PhantomData;
16
17#[derive(Clone)]
18pub struct Blake2bTranscript<E: PairingCurve> {
19    hasher: Blake2b512,
20    _phantom: PhantomData<E>,
21}
22
23impl<E: PairingCurve> Blake2bTranscript<E> {
24    pub fn new(domain_label: &[u8]) -> Self {
25        let mut hasher = Blake2b512::default();
26        hasher.update(domain_label);
27        Self {
28            hasher,
29            _phantom: PhantomData,
30        }
31    }
32
33    pub fn append_bytes_impl(&mut self, label: &[u8], bytes: &[u8]) {
34        self.hasher.update(label);
35        self.hasher.update((bytes.len() as u64).to_le_bytes());
36        self.hasher.update(bytes);
37    }
38
39    pub fn append_field_impl<F: PrimeField>(&mut self, label: &[u8], x: &F) {
40        self.append_bytes_impl(label, &x.into_bigint().to_bytes_le());
41    }
42
43    pub fn append_group_impl<G: CanonicalSerialize>(&mut self, label: &[u8], g: &G) {
44        let mut bytes = Vec::new();
45        g.serialize_compressed(&mut bytes)
46            .expect("Serialization should not fail");
47        self.append_bytes_impl(label, &bytes);
48    }
49
50    pub fn append_serde_impl<S: serde::Serialize>(&mut self, label: &[u8], s: &S) {
51        match bincode::serialize(s) {
52            Ok(bytes) => self.append_bytes_impl(label, &bytes),
53            Err(_) => panic!("Bincode serialization failed"),
54        }
55    }
56
57    pub fn challenge_scalar_impl<F: PrimeField>(&mut self, label: &[u8]) -> F {
58        self.hasher.update(label);
59
60        let h = self.hasher.clone();
61        let digest: Output<Blake2b512> = h.finalize();
62
63        let repr = digest.to_vec();
64        let fe = F::from_le_bytes_mod_order(&repr);
65
66        if fe.is_zero() {
67            panic!("Challenge scalar cannot be zero")
68        }
69
70        self.hasher.update(&repr);
71
72        fe
73    }
74
75    pub fn reset_impl(&mut self, domain_label: &[u8]) {
76        let mut hasher = Blake2b512::default();
77        hasher.update(domain_label);
78        self.hasher = hasher;
79        self._phantom = PhantomData;
80    }
81}
82
83impl Transcript for Blake2bTranscript<crate::backends::arkworks::BN254> {
84    type Curve = crate::backends::arkworks::BN254;
85
86    fn append_bytes(&mut self, label: &[u8], bytes: &[u8]) {
87        self.append_bytes_impl(label, bytes);
88    }
89
90    fn append_field(
91        &mut self,
92        label: &[u8],
93        x: &<<crate::backends::arkworks::BN254 as PairingCurve>::G1 as Group>::Scalar,
94    ) {
95        self.append_field_impl(label, &x.0);
96    }
97
98    fn append_group<G: Group + DorySerialize>(&mut self, label: &[u8], g: &G) {
99        let mut bytes: Vec<u8> = Vec::new();
100        g.serialize_with_mode(&mut bytes, Compress::Yes)
101            .expect("DorySerialize should not fail");
102        self.append_bytes_impl(label, &bytes);
103    }
104
105    fn append_serde<S: DorySerialize>(&mut self, label: &[u8], s: &S) {
106        let mut bytes: Vec<u8> = Vec::new();
107        s.serialize_with_mode(&mut bytes, Compress::Yes)
108            .expect("DorySerialize should not fail");
109        self.append_bytes_impl(label, &bytes);
110    }
111
112    fn challenge_scalar(&mut self, label: &[u8]) -> crate::backends::arkworks::ArkFr {
113        use crate::backends::arkworks::ArkFr;
114        ArkFr(self.challenge_scalar_impl(label))
115    }
116
117    fn reset(&mut self, domain_label: &[u8]) {
118        self.reset_impl(domain_label);
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use crate::backends::arkworks::BN254;
126
127    #[test]
128    fn transcript_consistency() {
129        let mut t1: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
130        let mut t2: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
131
132        // Same sequence of messages => same challenge
133        t1.append_bytes(b"m", b"hello");
134        t2.append_bytes(b"m", b"hello");
135
136        let c1 = t1.challenge_scalar(b"x");
137        let c2 = t2.challenge_scalar(b"x");
138
139        assert_eq!(c1, c2);
140    }
141
142    #[test]
143    fn transcript_different_messages() {
144        let mut t1: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
145        let mut t2: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
146
147        t1.append_bytes(b"m", b"hello");
148        t2.append_bytes(b"m", b"world");
149
150        let c1 = t1.challenge_scalar(b"x");
151        let c2 = t2.challenge_scalar(b"x");
152
153        assert_ne!(c1, c2);
154    }
155}