jf_rescue/
commitment.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! Implements a rescue hash based commitment scheme.
8
9use crate::{crhf::FixedLengthRescueCRHF, RescueError, RescueParameter};
10use ark_std::{borrow::Borrow, marker::PhantomData, string::ToString};
11use jf_commitment::CommitmentScheme;
12use jf_crhf::CRHF;
13
14/// Glorified bool type;
15type VerificationResult = Result<(), ()>;
16
17#[derive(Debug, Default, Clone, PartialEq, Eq)]
18/// Rescue-based Commitment instance for fixed-length input
19///
20/// ## Note
21/// the current ugly existence of `INPUT_LEN_PLUS_ONE` is due to unstable
22/// feature of using const generic in expression (namely can't use `INPUT_LEN +
23/// 1` in code).
24// FIXME: (alex) when `feature(generic_const_exprs)` is stable, we should remove
25// the third generic param. See more: https://github.com/rust-lang/rust/issues/76560
26pub struct FixedLengthRescueCommitment<
27    F: RescueParameter,
28    const INPUT_LEN: usize,
29    const INPUT_LEN_PLUS_ONE: usize,
30>(PhantomData<F>);
31
32impl<F: RescueParameter, const INPUT_LEN: usize, const INPUT_LEN_PLUS_ONE: usize> CommitmentScheme
33    for FixedLengthRescueCommitment<F, INPUT_LEN, INPUT_LEN_PLUS_ONE>
34{
35    type Input = [F; INPUT_LEN];
36    type Output = F;
37    type Randomness = F;
38    type Error = RescueError;
39
40    fn commit<T: Borrow<Self::Input>>(
41        input: T,
42        r: Option<&Self::Randomness>,
43    ) -> Result<Self::Output, Self::Error> {
44        let mut msg = [F::zero(); INPUT_LEN_PLUS_ONE];
45        msg[0] = *r.ok_or_else(|| {
46            RescueError::ParameterError("Expecting a blinding factor".to_string())
47        })?;
48        msg[1..INPUT_LEN_PLUS_ONE].copy_from_slice(&input.borrow()[..(INPUT_LEN)]);
49
50        Ok(FixedLengthRescueCRHF::<F, INPUT_LEN_PLUS_ONE, 1>::evaluate(&msg)?[0])
51    }
52
53    fn verify<T: Borrow<Self::Input>>(
54        input: T,
55        r: Option<&Self::Randomness>,
56        comm: &Self::Output,
57    ) -> Result<VerificationResult, Self::Error> {
58        if <Self as CommitmentScheme>::commit(input, r)? == *comm {
59            Ok(Ok(()))
60        } else {
61            Ok(Err(()))
62        }
63    }
64}
65
66#[cfg(test)]
67mod test {
68    use crate::{
69        commitment::{CommitmentScheme, FixedLengthRescueCommitment},
70        crhf::RescueCRHF,
71        CRHF_RATE,
72    };
73    use ark_bls12_377::Fq as Fq377;
74    use ark_bn254::Fq as Fq254;
75    use ark_ed_on_bls12_377::Fq as FqEd377;
76    use ark_ed_on_bls12_381::Fq as FqEd381;
77    use ark_ed_on_bls12_381_bandersnatch::Fq as FqEd381b;
78    use ark_ed_on_bn254::Fq as FqEd254;
79    use ark_ff::UniformRand;
80    use ark_std::vec;
81
82    macro_rules! test_commit {
83        ($tr:tt) => {
84            let mut prng = jf_utils::test_rng();
85
86            let input = [$tr::from(1u64), $tr::from(2u64), $tr::from(3u64)];
87            let blind = $tr::rand(&mut prng);
88
89            let c = FixedLengthRescueCommitment::<$tr, 3, 4>::commit(&input, Some(&blind)).unwrap();
90            assert!(
91                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&input, Some(&blind), &c)
92                    .unwrap()
93                    .is_ok()
94            );
95            // test for correctness
96            let mut msg = vec![blind];
97            msg.extend_from_slice(&input);
98            if (input.len() + 1) % CRHF_RATE == 0 {
99                assert_eq!(c, RescueCRHF::sponge_no_padding(&msg, 1).unwrap()[0])
100            } else {
101                assert_eq!(c, RescueCRHF::sponge_with_zero_padding(&msg, 1)[0])
102            }
103
104            // smaller input size
105            let bad_input = [input[0], input[1]];
106            assert!(
107                FixedLengthRescueCommitment::<$tr, 2, 3>::verify(&bad_input, Some(&blind), &c)
108                    .unwrap()
109                    .is_err()
110            );
111            // bad blinding factor
112            let bad_blind = blind + $tr::from(1u8);
113            assert!(
114                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&input, Some(&bad_blind), &c)
115                    .unwrap()
116                    .is_err()
117            );
118            // bad input
119            let bad_input = [$tr::from(2u64), $tr::from(1u64), $tr::from(3u64)];
120            assert!(
121                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&bad_input, Some(&blind), &c)
122                    .unwrap()
123                    .is_err()
124            );
125        };
126    }
127
128    #[test]
129    fn test_commit() {
130        test_commit!(FqEd254);
131        test_commit!(FqEd377);
132        test_commit!(FqEd381);
133        test_commit!(FqEd381b);
134        test_commit!(Fq377);
135        test_commit!(Fq254);
136    }
137}