Skip to content

Commit 2e4fc0f

Browse files
committed
Put table back and simplified FS code
1 parent b8a0dd0 commit 2e4fc0f

File tree

2 files changed

+77
-118
lines changed

2 files changed

+77
-118
lines changed

crates/aptos-dkg/src/dlog/bsgs.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ use std::collections::HashMap;
1212
/// - `baby_table`: precomputed HashMap from `C::Affine.to_compressed()` |---> exponent
1313
/// - `m`: size of the baby-step table
1414
#[allow(non_snake_case)]
15-
pub fn dlog<C: CurveGroup>(G: C, H: C, baby_table: &HashMap<Vec<u8>, u32>, m: u32) -> Option<u32> {
15+
pub fn baby_step_giant_step<C: CurveGroup, const N: usize>(
16+
G: C,
17+
H: C,
18+
baby_table: &HashMap<[u8; N], u64>,
19+
m: u64,
20+
) -> Option<u64> {
1621
let G_neg_m = G * -C::ScalarField::from(m);
1722

1823
let mut gamma = H;
19-
let size = gamma.compressed_size();
2024

2125
for i in 0..m {
22-
let mut buf = vec![0u8; size];
23-
gamma.serialize_compressed(&mut buf[..]).unwrap();
26+
let mut buf = [0u8; N];
27+
gamma.serialize_compressed(&mut &mut buf[..]).unwrap();
2428

2529
if let Some(&j) = baby_table.get(&buf) {
2630
return Some(i * m + j);
@@ -32,47 +36,47 @@ pub fn dlog<C: CurveGroup>(G: C, H: C, baby_table: &HashMap<Vec<u8>, u32>, m: u3
3236
None
3337
}
3438

39+
/// Build a baby-step table of size `m`
40+
///
41+
/// Returns a HashMap: `C::Affine.to_compressed() |---> exponent`
3542
#[allow(non_snake_case)]
36-
pub fn dlog_vec<C: CurveGroup>(
37-
G: C,
38-
H_vec: &[C],
39-
baby_table: &HashMap<Vec<u8>, u32>,
40-
m: u32,
41-
) -> Option<Vec<u32>> {
42-
let mut result = Vec::with_capacity(H_vec.len());
43-
44-
for H in H_vec {
45-
if let Some(x) = dlog(G, *H, baby_table, m) {
46-
result.push(x);
47-
} else {
48-
return None; // fail early if any element cannot be solved
49-
}
43+
pub fn build_baby_table<C: CurveGroup, const N: usize>(G: C, m: u64) -> HashMap<[u8; N], u64> {
44+
let mut table = HashMap::with_capacity(m as usize);
45+
let mut current = C::zero();
46+
47+
for j in 0..m {
48+
let mut buf = [0u8; N];
49+
current.serialize_compressed(&mut &mut buf[..]).unwrap();
50+
table.insert(buf, j);
51+
current += G;
5052
}
5153

52-
Some(result)
54+
table
5355
}
5456

5557
#[cfg(test)]
5658
mod tests {
5759
use super::*;
58-
use crate::dlog;
5960
use ark_bn254::G1Projective;
6061
use ark_ec::PrimeGroup;
6162

63+
const COMPRESSED_SIZE: usize = 48;
64+
6265
#[allow(non_snake_case)]
6366
#[test]
64-
fn test_bsgs_bn254_exhaustive() {
67+
fn test_bsgs_bn254_random() {
6568
let G = G1Projective::generator();
6669
let m = 1 << 4;
6770

68-
let baby_table = dlog::table::build::<G1Projective>(G, m);
71+
let baby_table = build_baby_table::<G1Projective, COMPRESSED_SIZE>(G, m);
6972

70-
// Test all values of x from 0 to m-1
73+
// Test all values of x from 0 to m^2 - 1
7174
for x in 0..m * m {
7275
let H = G * ark_bn254::Fr::from(x as u32);
7376

7477
let recovered =
75-
dlog::<G1Projective>(G, H, &baby_table, m).expect("Failed to recover discrete log");
78+
baby_step_giant_step::<G1Projective, COMPRESSED_SIZE>(G, H, &baby_table, m)
79+
.expect("Failed to recover discrete log");
7680

7781
assert_eq!(recovered, x, "Discrete log mismatch for x = {}", x);
7882
}

crates/aptos-dkg/src/fiat_shamir.rs

Lines changed: 49 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
1010
use crate::{
1111
pvss::traits::Transcript, range_proofs::traits::BatchedRangeProof, sigma_protocol,
12-
sigma_protocol::homomorphism, utils::random::random_scalar_from_uniform_bytes, Scalar,
12+
sigma_protocol::homomorphism, Scalar,
1313
};
1414
use aptos_crypto::ValidCryptoMaterial;
1515
use ark_ec::pairing::Pairing;
1616
use ark_ff::PrimeField;
1717
use ark_serialize::CanonicalSerialize;
18-
use ff::PrimeField as FfPrimeField;
1918
use serde::Serialize;
2019

2120
#[allow(dead_code)] // Will be used in the new PVSS
@@ -30,89 +29,47 @@ pub const PVSS_DOM_SEP: &[u8; 26] = b"APTOS_PVSS_FIAT_SHAMIR_DST";
3029
/// ⚠️ This trait is intentionally private: functions like `challenge_scalars`
3130
/// should **only** be used internally to ensure properly
3231
/// labelled scalar generation across protocols.
33-
trait ScalarProtocol<S: FromBytes> {
34-
fn challenge_full_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<S>;
32+
//
33+
// TODO: Again, seems that ideally Scalar<E> should become Scalar<F> instead
34+
trait ScalarProtocol<E: Pairing> {
35+
fn challenge_full_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<Scalar<E>>;
3536

36-
fn challenge_full_scalar(&mut self, label: &[u8]) -> S {
37+
fn challenge_full_scalar(&mut self, label: &[u8]) -> Scalar<E> {
3738
self.challenge_full_scalars(label, 1)[0]
3839
}
3940

40-
fn challenge_128bit_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<S>;
41+
fn challenge_128bit_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<Scalar<E>>;
4142
}
4243

43-
/// Trait for types that can be constructed from uniform bytes or 128-bit random bytes
44-
trait FromBytes: Copy {
45-
const BYTE_SIZE: usize;
46-
47-
/// Construct scalars, each from a uniform byte slice (usually larger than 16 bytes)
48-
fn from_uniform_bytes(bytes: &[u8]) -> Self;
49-
50-
/// Construct scalars, each from exactly 16 bytes (128-bit randomness)
51-
fn from_16_random_bytes(bytes: &[u8; 16]) -> Self;
52-
}
53-
54-
impl<E: Pairing> FromBytes for Scalar<E> {
55-
const BYTE_SIZE: usize = (E::ScalarField::MODULUS_BIT_SIZE as usize) / 8;
56-
57-
fn from_uniform_bytes(bytes: &[u8]) -> Self {
58-
assert_eq!(bytes.len(), 2 * Self::BYTE_SIZE);
59-
Self(E::ScalarField::from_le_bytes_mod_order(bytes))
60-
}
61-
62-
fn from_16_random_bytes(bytes: &[u8; 16]) -> Self {
63-
Self(E::ScalarField::from_le_bytes_mod_order(bytes))
64-
}
65-
}
66-
67-
// TODO: It's unlikely that this code will be useful in the near future...
68-
impl FromBytes for blstrs::Scalar {
69-
const BYTE_SIZE: usize = crate::SCALAR_NUM_BYTES;
70-
71-
fn from_uniform_bytes(bytes: &[u8]) -> Self {
72-
// No assert_eq needed here because it is enforced by the function below
73-
random_scalar_from_uniform_bytes(bytes.try_into().expect("Wrong byte length"))
74-
}
75-
76-
fn from_16_random_bytes(bytes: &[u8; 16]) -> Self {
77-
blstrs::Scalar::from_u128(u128::from_le_bytes(*bytes))
78-
}
79-
}
80-
81-
impl<S: FromBytes> ScalarProtocol<S> for merlin::Transcript {
82-
fn challenge_full_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<S> {
83-
let mut buf = vec![0u8; 2 * num_scalars * S::BYTE_SIZE];
84-
self.challenge_bytes(label, &mut buf); // Label is also appended here
85-
86-
let result = buf
87-
.chunks(2 * S::BYTE_SIZE)
88-
.map(S::from_uniform_bytes)
89-
.collect::<Vec<_>>();
44+
impl<E: Pairing> ScalarProtocol<E> for merlin::Transcript {
45+
fn challenge_full_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<Scalar<E>> {
46+
let byte_size = (E::ScalarField::MODULUS_BIT_SIZE as usize) / 8;
47+
let mut buf = vec![0u8; 2 * num_scalars * byte_size];
48+
self.challenge_bytes(label, &mut buf);
9049

91-
debug_assert_eq!(result.len(), num_scalars);
92-
result
50+
buf.chunks(2 * byte_size)
51+
.map(|chunk| Scalar(E::ScalarField::from_le_bytes_mod_order(chunk)))
52+
.collect()
9353
}
9454

95-
fn challenge_128bit_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<S> {
96-
// Allocate 16 bytes (128 bits) per scalar
55+
fn challenge_128bit_scalars(&mut self, label: &[u8], num_scalars: usize) -> Vec<Scalar<E>> {
9756
let mut buf = vec![0u8; num_scalars * 16];
9857
self.challenge_bytes(label, &mut buf);
9958

100-
let mut scalars = Vec::with_capacity(num_scalars);
101-
102-
for chunk in buf.chunks(16) {
103-
scalars.push(S::from_16_random_bytes(chunk.try_into().unwrap()));
104-
}
105-
106-
debug_assert_eq!(scalars.len(), num_scalars);
107-
scalars
59+
buf.chunks(16)
60+
.map(|chunk| {
61+
Scalar(E::ScalarField::from_le_bytes_mod_order(
62+
chunk.try_into().unwrap(),
63+
))
64+
})
65+
.collect()
10866
}
10967
}
11068

111-
// TODO: it may make sense to make an associated type Scalar of Transcript, then remove S here and replace it with T::Scalar. Or remove it entirely given that we now only use arkworks...
11269
#[allow(non_snake_case)]
11370
#[allow(private_bounds)]
11471
#[allow(dead_code)] // Will be used in the new PVSS
115-
pub trait PVSS<S: FromBytes, T: Transcript>: ScalarProtocol<S> {
72+
pub trait PVSS<E: Pairing, T: Transcript>: ScalarProtocol<E> {
11673
/// Append a domain separator for the PVSS protocol (in addition to the transcript-level DST used to initialise the FS transcript),
11774
/// consisting of a sharing configuration `sc`, which locks in the $t$ out of $n$ threshold.
11875
fn pvss_domain_sep(&mut self, sc: &T::SecretSharingConfig);
@@ -134,11 +91,11 @@ pub trait PVSS<S: FromBytes, T: Transcript>: ScalarProtocol<S> {
13491
fn append_transcript(&mut self, trx: &T);
13592

13693
/// Returns a random dual-code word check polynomial for the SCRAPE LDT test.
137-
fn challenge_dual_code_word_polynomial(&mut self, t: usize, n: usize) -> Vec<S>;
94+
fn challenge_dual_code_word_polynomial(&mut self, t: usize, n: usize) -> Vec<Scalar<E>>;
13895

13996
/// Returns one or more scalars `r` useful for doing linear combinations (e.g., combining
14097
/// pairings in the SCRAPE multipairing check using coefficients $1, r, r^2, r^3, \ldots$
141-
fn challenge_linear_combination_scalars(&mut self, num_scalars: usize) -> Vec<S>;
98+
fn challenge_linear_combination_scalars(&mut self, num_scalars: usize) -> Vec<Scalar<E>>;
14299
}
143100

144101
pub trait RangeProof<E: Pairing, B: BatchedRangeProof<E>> {
@@ -164,7 +121,7 @@ pub trait RangeProof<E: Pairing, B: BatchedRangeProof<E>> {
164121
}
165122

166123
#[allow(private_bounds)]
167-
pub trait SigmaProtocol<E: Pairing, H: homomorphism::Trait>: ScalarProtocol<Scalar<E>> {
124+
pub trait SigmaProtocol<E: Pairing, H: homomorphism::Trait>: ScalarProtocol<E> {
168125
fn append_sigma_protocol_sep(&mut self, dst: &[u8]);
169126

170127
/// Append the MSM bases of a sigma protocol.
@@ -186,7 +143,7 @@ pub trait SigmaProtocol<E: Pairing, H: homomorphism::Trait>: ScalarProtocol<Scal
186143
}
187144

188145
#[allow(non_snake_case)]
189-
impl<S: FromBytes, T: Transcript> PVSS<S, T> for merlin::Transcript {
146+
impl<E: Pairing, T: Transcript> PVSS<E, T> for merlin::Transcript {
190147
fn pvss_domain_sep(&mut self, sc: &T::SecretSharingConfig) {
191148
self.append_message(b"dom-sep", PVSS_DOM_SEP);
192149
self.append_message(b"scheme-name", T::scheme_name().as_bytes());
@@ -217,7 +174,7 @@ impl<S: FromBytes, T: Transcript> PVSS<S, T> for merlin::Transcript {
217174
fn append_auxs<A: Serialize>(&mut self, auxs: &[A]) {
218175
self.append_u64(b"auxs", auxs.len() as u64);
219176
for aux in auxs {
220-
<merlin::Transcript as PVSS<S, T>>::append_aux::<A>(self, aux);
177+
<merlin::Transcript as PVSS<E, T>>::append_aux::<A>(self, aux);
221178
}
222179
}
223180

@@ -230,17 +187,17 @@ impl<S: FromBytes, T: Transcript> PVSS<S, T> for merlin::Transcript {
230187
self.append_message(b"transcript", trx.to_bytes().as_slice());
231188
}
232189

233-
fn challenge_dual_code_word_polynomial(&mut self, t: usize, n_plus_1: usize) -> Vec<S> {
190+
fn challenge_dual_code_word_polynomial(&mut self, t: usize, n_plus_1: usize) -> Vec<Scalar<E>> {
234191
let num_coeffs = n_plus_1 - t;
235-
<merlin::Transcript as ScalarProtocol<S>>::challenge_full_scalars(
192+
<merlin::Transcript as ScalarProtocol<E>>::challenge_full_scalars(
236193
self,
237194
b"challenge_dual_code_word_polynomial",
238195
num_coeffs,
239196
)
240197
}
241198

242-
fn challenge_linear_combination_scalars(&mut self, num_scalars: usize) -> Vec<S> {
243-
<merlin::Transcript as ScalarProtocol<S>>::challenge_full_scalars(
199+
fn challenge_linear_combination_scalars(&mut self, num_scalars: usize) -> Vec<Scalar<E>> {
200+
<merlin::Transcript as ScalarProtocol<E>>::challenge_full_scalars(
244201
self,
245202
b"challenge_linear_combination",
246203
num_scalars,
@@ -250,17 +207,17 @@ impl<S: FromBytes, T: Transcript> PVSS<S, T> for merlin::Transcript {
250207

251208
#[allow(private_bounds)]
252209
#[allow(dead_code)] // Will be used in the new PVSS
253-
pub(crate) fn initialize_pvss_transcript<S: FromBytes, T: Transcript>(
210+
pub(crate) fn initialize_pvss_transcript<E: Pairing, T: Transcript>(
254211
sc: &T::SecretSharingConfig,
255212
pp: &T::PublicParameters,
256213
eks: &[T::EncryptPubKey],
257214
dst: &[u8],
258215
) -> merlin::Transcript {
259216
let mut fs_t = merlin::Transcript::new(dst);
260217

261-
<merlin::Transcript as PVSS<S, T>>::pvss_domain_sep(&mut fs_t, sc);
262-
<merlin::Transcript as PVSS<S, T>>::append_public_parameters(&mut fs_t, pp);
263-
<merlin::Transcript as PVSS<S, T>>::append_encryption_keys(&mut fs_t, eks);
218+
<merlin::Transcript as PVSS<E, T>>::pvss_domain_sep(&mut fs_t, sc);
219+
<merlin::Transcript as PVSS<E, T>>::append_public_parameters(&mut fs_t, pp);
220+
<merlin::Transcript as PVSS<E, T>>::append_encryption_keys(&mut fs_t, eks);
264221

265222
fs_t
266223
}
@@ -319,29 +276,27 @@ impl<E: Pairing, B: BatchedRangeProof<E>> RangeProof<E, B> for merlin::Transcrip
319276
}
320277

321278
fn challenges_for_quotient_polynomials(&mut self, ell: usize) -> Vec<E::ScalarField> {
322-
let challenges =
323-
<merlin::Transcript as ScalarProtocol<Scalar<E>>>::challenge_128bit_scalars(
324-
self,
325-
b"challenge_for_quotient_polynomials",
326-
ell + 1,
327-
);
279+
let challenges = <merlin::Transcript as ScalarProtocol<E>>::challenge_128bit_scalars(
280+
self,
281+
b"challenge_for_quotient_polynomials",
282+
ell + 1,
283+
);
328284

329285
Scalar::<E>::vec_into_inner(challenges)
330286
}
331287

332288
fn challenges_for_linear_combination(&mut self, num: usize) -> Vec<E::ScalarField> {
333-
let challenges =
334-
<merlin::Transcript as ScalarProtocol<Scalar<E>>>::challenge_128bit_scalars(
335-
self,
336-
b"challenge_for_linear_combination",
337-
num,
338-
);
289+
let challenges = <merlin::Transcript as ScalarProtocol<E>>::challenge_128bit_scalars(
290+
self,
291+
b"challenge_for_linear_combination",
292+
num,
293+
);
339294

340295
Scalar::<E>::vec_into_inner(challenges)
341296
}
342297

343298
fn challenge_from_verifier(&mut self) -> E::ScalarField {
344-
<merlin::Transcript as ScalarProtocol<Scalar<E>>>::challenge_full_scalar(
299+
<merlin::Transcript as ScalarProtocol<E>>::challenge_full_scalar(
345300
self,
346301
b"verifier_challenge_for_linear_combination",
347302
)
@@ -397,7 +352,7 @@ where
397352
}
398353

399354
fn challenge_for_sigma_protocol(&mut self) -> E::ScalarField {
400-
<merlin::Transcript as ScalarProtocol<Scalar<E>>>::challenge_full_scalar(
355+
<merlin::Transcript as ScalarProtocol<E>>::challenge_full_scalar(
401356
self,
402357
b"challenge_sigma_protocol",
403358
)

0 commit comments

Comments
 (0)