jf_rescue/
commitment.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2022 Espresso Systems (espressosys.com)
// This file is part of the Jellyfish library.

// You should have received a copy of the MIT License
// along with the Jellyfish library. If not, see <https://mit-license.org/>.

//! Implements a rescue hash based commitment scheme.

use crate::{crhf::FixedLengthRescueCRHF, RescueError, RescueParameter};
use ark_std::{borrow::Borrow, marker::PhantomData, string::ToString};
use jf_commitment::CommitmentScheme;
use jf_crhf::CRHF;

/// Glorified bool type;
type VerificationResult = Result<(), ()>;

#[derive(Debug, Default, Clone, PartialEq, Eq)]
/// Rescue-based Commitment instance for fixed-length input
///
/// ## Note
/// the current ugly existence of `INPUT_LEN_PLUS_ONE` is due to unstable
/// feature of using const generic in expression (namely can't use `INPUT_LEN +
/// 1` in code).
// FIXME: (alex) when `feature(generic_const_exprs)` is stable, we should remove
// the third generic param. See more: https://github.com/rust-lang/rust/issues/76560
pub struct FixedLengthRescueCommitment<
    F: RescueParameter,
    const INPUT_LEN: usize,
    const INPUT_LEN_PLUS_ONE: usize,
>(PhantomData<F>);

impl<F: RescueParameter, const INPUT_LEN: usize, const INPUT_LEN_PLUS_ONE: usize> CommitmentScheme
    for FixedLengthRescueCommitment<F, INPUT_LEN, INPUT_LEN_PLUS_ONE>
{
    type Input = [F; INPUT_LEN];
    type Output = F;
    type Randomness = F;
    type Error = RescueError;

    fn commit<T: Borrow<Self::Input>>(
        input: T,
        r: Option<&Self::Randomness>,
    ) -> Result<Self::Output, Self::Error> {
        let mut msg = [F::zero(); INPUT_LEN_PLUS_ONE];
        msg[0] = *r.ok_or_else(|| {
            RescueError::ParameterError("Expecting a blinding factor".to_string())
        })?;
        msg[1..INPUT_LEN_PLUS_ONE].copy_from_slice(&input.borrow()[..(INPUT_LEN)]);

        Ok(FixedLengthRescueCRHF::<F, INPUT_LEN_PLUS_ONE, 1>::evaluate(&msg)?[0])
    }

    fn verify<T: Borrow<Self::Input>>(
        input: T,
        r: Option<&Self::Randomness>,
        comm: &Self::Output,
    ) -> Result<VerificationResult, Self::Error> {
        if <Self as CommitmentScheme>::commit(input, r)? == *comm {
            Ok(Ok(()))
        } else {
            Ok(Err(()))
        }
    }
}

#[cfg(test)]
mod test {
    use crate::{
        commitment::{CommitmentScheme, FixedLengthRescueCommitment},
        crhf::RescueCRHF,
        CRHF_RATE,
    };
    use ark_bls12_377::Fq as Fq377;
    use ark_bn254::Fq as Fq254;
    use ark_ed_on_bls12_377::Fq as FqEd377;
    use ark_ed_on_bls12_381::Fq as FqEd381;
    use ark_ed_on_bls12_381_bandersnatch::Fq as FqEd381b;
    use ark_ed_on_bn254::Fq as FqEd254;
    use ark_ff::UniformRand;
    use ark_std::vec;

    macro_rules! test_commit {
        ($tr:tt) => {
            let mut prng = jf_utils::test_rng();

            let input = [$tr::from(1u64), $tr::from(2u64), $tr::from(3u64)];
            let blind = $tr::rand(&mut prng);

            let c = FixedLengthRescueCommitment::<$tr, 3, 4>::commit(&input, Some(&blind)).unwrap();
            assert!(
                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&input, Some(&blind), &c)
                    .unwrap()
                    .is_ok()
            );
            // test for correctness
            let mut msg = vec![blind];
            msg.extend_from_slice(&input);
            if (input.len() + 1) % CRHF_RATE == 0 {
                assert_eq!(c, RescueCRHF::sponge_no_padding(&msg, 1).unwrap()[0])
            } else {
                assert_eq!(c, RescueCRHF::sponge_with_zero_padding(&msg, 1)[0])
            }

            // smaller input size
            let bad_input = [input[0], input[1]];
            assert!(
                FixedLengthRescueCommitment::<$tr, 2, 3>::verify(&bad_input, Some(&blind), &c)
                    .unwrap()
                    .is_err()
            );
            // bad blinding factor
            let bad_blind = blind + $tr::from(1u8);
            assert!(
                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&input, Some(&bad_blind), &c)
                    .unwrap()
                    .is_err()
            );
            // bad input
            let bad_input = [$tr::from(2u64), $tr::from(1u64), $tr::from(3u64)];
            assert!(
                FixedLengthRescueCommitment::<$tr, 3, 4>::verify(&bad_input, Some(&blind), &c)
                    .unwrap()
                    .is_err()
            );
        };
    }

    #[test]
    fn test_commit() {
        test_commit!(FqEd254);
        test_commit!(FqEd377);
        test_commit!(FqEd381);
        test_commit!(FqEd381b);
        test_commit!(Fq377);
        test_commit!(Fq254);
    }
}