2022-07-26 02:05:15 -05:00
|
|
|
// Required to be for this entire file, which isn't an issue, as it wouldn't bind to the static
|
|
|
|
|
#![allow(non_upper_case_globals)]
|
|
|
|
|
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
use curve25519_dalek::edwards::EdwardsPoint as DalekPoint;
|
2022-07-26 08:06:56 -04:00
|
|
|
|
2022-07-26 02:05:15 -05:00
|
|
|
use group::{ff::Field, Group};
|
2022-07-31 23:12:45 -04:00
|
|
|
use dalek_ff_group::{Scalar, EdwardsPoint};
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
use multiexp::multiexp as multiexp_const;
|
2022-07-26 02:05:15 -05:00
|
|
|
|
|
|
|
|
use crate::{
|
2022-07-27 04:05:43 -05:00
|
|
|
H as DALEK_H, Commitment, hash, hash_to_scalar as dalek_hash,
|
2022-07-31 23:12:45 -04:00
|
|
|
ringct::hash_to_point::raw_hash_to_point, serialize::write_varint,
|
2022-07-26 02:05:15 -05:00
|
|
|
};
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) use crate::ringct::bulletproofs::scalar_vector::*;
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-26 08:06:56 -04:00
|
|
|
// Bring things into ff/group
|
|
|
|
|
lazy_static! {
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) static ref INV_EIGHT: Scalar = Scalar::from(8u8).invert().unwrap();
|
|
|
|
|
pub(crate) static ref H: EdwardsPoint = EdwardsPoint(*DALEK_H);
|
2022-07-26 08:06:56 -04:00
|
|
|
}
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn hash_to_scalar(data: &[u8]) -> Scalar {
|
2022-07-26 03:25:57 -04:00
|
|
|
Scalar(dalek_hash(data))
|
2022-07-26 02:05:15 -05:00
|
|
|
}
|
|
|
|
|
|
2022-07-26 08:06:56 -04:00
|
|
|
// Components common between variants
|
|
|
|
|
pub(crate) const MAX_M: usize = 16;
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) const N: usize = 64;
|
|
|
|
|
pub(crate) const MAX_MN: usize = MAX_M * N;
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) struct Generators {
|
|
|
|
|
pub(crate) G: Vec<EdwardsPoint>,
|
|
|
|
|
pub(crate) H: Vec<EdwardsPoint>,
|
2022-07-26 08:06:56 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn generators_core(prefix: &'static [u8]) -> Generators {
|
2022-07-26 08:06:56 -04:00
|
|
|
let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) };
|
|
|
|
|
for i in 0 .. MAX_MN {
|
|
|
|
|
let i = 2 * i;
|
|
|
|
|
|
|
|
|
|
let mut even = (*H).compress().to_bytes().to_vec();
|
|
|
|
|
even.extend(prefix);
|
|
|
|
|
let mut odd = even.clone();
|
|
|
|
|
|
|
|
|
|
write_varint(&i.try_into().unwrap(), &mut even).unwrap();
|
|
|
|
|
write_varint(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
|
|
|
|
res.H.push(EdwardsPoint(raw_hash_to_point(hash(&even))));
|
|
|
|
|
res.G.push(EdwardsPoint(raw_hash_to_point(hash(&odd))));
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn prove_multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
|
|
|
|
multiexp_const(pairs) * *INV_EIGHT
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-27 04:05:43 -05:00
|
|
|
// TODO: Have this take in other, multiplied by G, and do a single multiexp
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn vector_exponent(
|
|
|
|
|
generators: &Generators,
|
|
|
|
|
a: &ScalarVector,
|
|
|
|
|
b: &ScalarVector,
|
|
|
|
|
) -> EdwardsPoint {
|
2022-07-26 05:31:15 -04:00
|
|
|
debug_assert_eq!(a.len(), b.len());
|
2022-07-26 08:06:56 -04:00
|
|
|
(a * &generators.G[.. a.len()]) + (b * &generators.H[.. b.len()])
|
2022-07-26 02:05:15 -05:00
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn hash_cache(cache: &mut Scalar, mash: &[[u8; 32]]) -> Scalar {
|
2022-07-26 02:05:15 -05:00
|
|
|
let slice =
|
|
|
|
|
&[cache.to_bytes().as_ref(), mash.iter().cloned().flatten().collect::<Vec<_>>().as_ref()]
|
|
|
|
|
.concat();
|
|
|
|
|
*cache = hash_to_scalar(slice);
|
|
|
|
|
*cache
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn MN(outputs: usize) -> (usize, usize, usize) {
|
2022-07-26 02:05:15 -05:00
|
|
|
let logN = 6;
|
2022-07-26 05:31:15 -04:00
|
|
|
debug_assert_eq!(N, 1 << logN);
|
2022-07-26 02:05:15 -05:00
|
|
|
|
|
|
|
|
let mut logM = 0;
|
|
|
|
|
let mut M;
|
|
|
|
|
while {
|
|
|
|
|
M = 1 << logM;
|
2022-07-26 08:06:56 -04:00
|
|
|
(M <= MAX_M) && (M < outputs)
|
2022-07-26 02:05:15 -05:00
|
|
|
} {
|
|
|
|
|
logM += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-26 08:06:56 -04:00
|
|
|
(logM + logN, M, M * N)
|
|
|
|
|
}
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn bit_decompose(commitments: &[Commitment]) -> (ScalarVector, ScalarVector) {
|
2022-07-26 08:06:56 -04:00
|
|
|
let (_, M, MN) = MN(commitments.len());
|
|
|
|
|
|
2022-07-27 04:05:43 -05:00
|
|
|
let sv = commitments.iter().map(|c| Scalar::from(c.amount)).collect::<Vec<_>>();
|
2022-07-26 02:05:15 -05:00
|
|
|
let mut aL = ScalarVector::new(MN);
|
|
|
|
|
let mut aR = ScalarVector::new(MN);
|
|
|
|
|
|
|
|
|
|
for j in 0 .. M {
|
|
|
|
|
for i in (0 .. N).rev() {
|
|
|
|
|
if (j < sv.len()) && ((sv[j][i / 8] & (1u8 << (i % 8))) != 0) {
|
|
|
|
|
aL.0[(j * N) + i] = Scalar::one();
|
|
|
|
|
} else {
|
|
|
|
|
aR.0[(j * N) + i] = -Scalar::one();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-26 08:06:56 -04:00
|
|
|
(aL, aR)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn hash_commitments<C: IntoIterator<Item = DalekPoint>>(
|
2022-07-31 21:45:53 -05:00
|
|
|
commitments: C,
|
|
|
|
|
) -> (Scalar, Vec<EdwardsPoint>) {
|
|
|
|
|
let V = commitments.into_iter().map(|c| EdwardsPoint(c) * *INV_EIGHT).collect::<Vec<_>>();
|
|
|
|
|
(hash_to_scalar(&V.iter().flat_map(|V| V.compress().to_bytes()).collect::<Vec<_>>()), V)
|
2022-07-26 08:06:56 -04:00
|
|
|
}
|
2022-07-26 02:05:15 -05:00
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn alpha_rho<R: RngCore + CryptoRng>(
|
2022-07-26 08:06:56 -04:00
|
|
|
rng: &mut R,
|
|
|
|
|
generators: &Generators,
|
|
|
|
|
aL: &ScalarVector,
|
|
|
|
|
aR: &ScalarVector,
|
|
|
|
|
) -> (Scalar, EdwardsPoint) {
|
2022-07-27 04:05:43 -05:00
|
|
|
let ar = Scalar::random(rng);
|
|
|
|
|
(ar, (vector_exponent(generators, aL, aR) + (EdwardsPoint::generator() * ar)) * *INV_EIGHT)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) fn LR_statements(
|
2022-07-27 04:05:43 -05:00
|
|
|
a: &ScalarVector,
|
|
|
|
|
G_i: &[EdwardsPoint],
|
|
|
|
|
b: &ScalarVector,
|
|
|
|
|
H_i: &[EdwardsPoint],
|
|
|
|
|
cL: Scalar,
|
|
|
|
|
U: EdwardsPoint,
|
|
|
|
|
) -> Vec<(Scalar, EdwardsPoint)> {
|
|
|
|
|
let mut res = a
|
|
|
|
|
.0
|
|
|
|
|
.iter()
|
|
|
|
|
.cloned()
|
|
|
|
|
.zip(G_i.iter().cloned())
|
|
|
|
|
.chain(b.0.iter().cloned().zip(H_i.iter().cloned()))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
res.push((cL, U));
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
2022-07-31 23:12:45 -04:00
|
|
|
pub(crate) static ref TWO_N: ScalarVector = ScalarVector::powers(Scalar::from(2u8), N);
|
2022-07-27 04:05:43 -05:00
|
|
|
}
|
2022-08-01 23:30:24 -04:00
|
|
|
|
|
|
|
|
pub(crate) fn challenge_products(w: &[Scalar], winv: &[Scalar]) -> Vec<Scalar> {
|
|
|
|
|
let mut products = vec![Scalar::zero(); 1 << w.len()];
|
|
|
|
|
products[0] = winv[0];
|
|
|
|
|
products[1] = w[0];
|
|
|
|
|
for j in 1 .. w.len() {
|
|
|
|
|
let mut slots = (1 << (j + 1)) - 1;
|
|
|
|
|
while slots > 0 {
|
|
|
|
|
products[slots] = products[slots / 2] * w[j];
|
|
|
|
|
products[slots - 1] = products[slots / 2] * winv[j];
|
|
|
|
|
slots = slots.saturating_sub(2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanity check as if the above failed to populate, it'd be critical
|
|
|
|
|
for w in &products {
|
|
|
|
|
debug_assert!(!bool::from(w.is_zero()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
products
|
|
|
|
|
}
|