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
use bitvec::{self, BitVec};
use ff::PrimeFieldRepr;
use fil_sapling_crypto::jubjub::JubjubBls12;
use fil_sapling_crypto::pedersen_hash::{pedersen_hash, Personalization};
use paired::bls12_381::{Bls12, Fr, FrRepr};
use crate::fr32::bytes_into_frs;
lazy_static! {
pub static ref JJ_PARAMS: JubjubBls12 = JubjubBls12::new();
}
pub const PEDERSEN_BLOCK_SIZE: usize = 256;
pub const PEDERSEN_BLOCK_BYTES: usize = PEDERSEN_BLOCK_SIZE / 8;
pub fn pedersen(data: &[u8]) -> Fr {
pedersen_hash::<Bls12, _>(
Personalization::NoteCommitment,
BitVec::<bitvec::LittleEndian, u8>::from(data)
.iter()
.take(data.len() * 8),
&JJ_PARAMS,
)
.into_xy()
.0
}
pub fn pedersen_md_no_padding(data: &[u8]) -> Fr {
assert!(
data.len() >= 2 * PEDERSEN_BLOCK_BYTES,
"must be at least 2 block sizes long, got {}bits",
data.len()
);
assert_eq!(
data.len() % PEDERSEN_BLOCK_BYTES,
0,
"input must be a multiple of the blocksize"
);
let mut chunks = data.chunks(PEDERSEN_BLOCK_BYTES);
let mut cur = Vec::with_capacity(2 * PEDERSEN_BLOCK_BYTES);
cur.resize(PEDERSEN_BLOCK_BYTES, 0);
cur[0..PEDERSEN_BLOCK_BYTES].copy_from_slice(chunks.nth(0).unwrap());
for block in chunks {
cur.resize(2 * PEDERSEN_BLOCK_BYTES, 0);
cur[PEDERSEN_BLOCK_BYTES..].copy_from_slice(block);
pedersen_compression(&mut cur);
}
let frs = bytes_into_frs::<Bls12>(&cur[0..PEDERSEN_BLOCK_BYTES])
.expect("pedersen must generate valid fr elements");
assert_eq!(frs.len(), 1);
frs[0]
}
pub fn pedersen_compression(bytes: &mut Vec<u8>) {
let bits = BitVec::<bitvec::LittleEndian, u8>::from(&bytes[..]);
let (x, _) = pedersen_hash::<Bls12, _>(
Personalization::NoteCommitment,
bits.iter().take(bytes.len() * 8),
&JJ_PARAMS,
)
.into_xy();
let x: FrRepr = x.into();
bytes.truncate(0);
x.write_le(bytes).expect("failed to write result hash");
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::bytes_into_bits;
use ff::Field;
use paired::bls12_381::Fr;
use rand::{Rng, SeedableRng, XorShiftRng};
#[test]
fn test_bit_vec_le() {
let bytes = b"ABC";
let bits = bytes_into_bits(bytes);
let mut bits2 = core::iter::repeat(false)
.take(bits.len())
.collect::<BitVec<bitvec::LittleEndian, u8>>();
bits2.as_mut()[0..bytes.len()].copy_from_slice(&bytes[..]);
assert_eq!(bits, bits2.iter().collect::<Vec<bool>>());
}
#[test]
fn test_pedersen_compression() {
let bytes = b"some bytes";
let mut data = vec![0; bytes.len()];
data.copy_from_slice(&bytes[..]);
pedersen_compression(&mut data);
let expected = vec![
213, 235, 66, 156, 7, 85, 177, 39, 249, 31, 160, 247, 29, 106, 36, 46, 225, 71, 116,
23, 1, 89, 82, 149, 45, 189, 27, 189, 144, 98, 23, 98,
];
assert_eq!(expected, data);
}
#[test]
fn test_pedersen_md_no_padding() {
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for i in 2..5 {
let x: Vec<u8> = (0..i * 32).map(|_| rng.gen()).collect();
let hashed = pedersen_md_no_padding(x.as_slice());
assert_ne!(hashed, Fr::zero());
}
}
}