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 challenge_scalar_impl<F: PrimeField>(&mut self, label: &[u8]) -> F {
51        self.hasher.update(label);
52
53        let h = self.hasher.clone();
54        let digest: Output<Blake2b512> = h.finalize();
55
56        let repr = digest.to_vec();
57        let fe = F::from_le_bytes_mod_order(&repr);
58
59        if fe.is_zero() {
60            panic!("Challenge scalar cannot be zero")
61        }
62
63        self.hasher.update(&repr);
64
65        fe
66    }
67
68    pub fn reset_impl(&mut self, domain_label: &[u8]) {
69        let mut hasher = Blake2b512::default();
70        hasher.update(domain_label);
71        self.hasher = hasher;
72        self._phantom = PhantomData;
73    }
74}
75
76impl Transcript for Blake2bTranscript<crate::backends::arkworks::BN254> {
77    type Curve = crate::backends::arkworks::BN254;
78
79    fn append_bytes(&mut self, label: &[u8], bytes: &[u8]) {
80        self.append_bytes_impl(label, bytes);
81    }
82
83    fn append_field(
84        &mut self,
85        label: &[u8],
86        x: &<<crate::backends::arkworks::BN254 as PairingCurve>::G1 as Group>::Scalar,
87    ) {
88        self.append_field_impl(label, &x.0);
89    }
90
91    fn append_group<G: Group + DorySerialize>(&mut self, label: &[u8], g: &G) {
92        let mut bytes: Vec<u8> = Vec::new();
93        g.serialize_with_mode(&mut bytes, Compress::Yes)
94            .expect("DorySerialize should not fail");
95        self.append_bytes_impl(label, &bytes);
96    }
97
98    fn append_serde<S: DorySerialize>(&mut self, label: &[u8], s: &S) {
99        let mut bytes: Vec<u8> = Vec::new();
100        s.serialize_with_mode(&mut bytes, Compress::Yes)
101            .expect("DorySerialize should not fail");
102        self.append_bytes_impl(label, &bytes);
103    }
104
105    fn challenge_scalar(&mut self, label: &[u8]) -> crate::backends::arkworks::ArkFr {
106        use crate::backends::arkworks::ArkFr;
107        ArkFr(self.challenge_scalar_impl(label))
108    }
109
110    fn reset(&mut self, domain_label: &[u8]) {
111        self.reset_impl(domain_label);
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use crate::backends::arkworks::BN254;
119
120    #[test]
121    fn transcript_consistency() {
122        let mut t1: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
123        let mut t2: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
124
125        // Same sequence of messages => same challenge
126        t1.append_bytes(b"m", b"hello");
127        t2.append_bytes(b"m", b"hello");
128
129        let c1 = t1.challenge_scalar(b"x");
130        let c2 = t2.challenge_scalar(b"x");
131
132        assert_eq!(c1, c2);
133    }
134
135    #[test]
136    fn transcript_different_messages() {
137        let mut t1: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
138        let mut t2: Blake2bTranscript<BN254> = Blake2bTranscript::new(b"demo");
139
140        t1.append_bytes(b"m", b"hello");
141        t2.append_bytes(b"m", b"world");
142
143        let c1 = t1.challenge_scalar(b"x");
144        let c2 = t2.challenge_scalar(b"x");
145
146        assert_ne!(c1, c2);
147    }
148}