Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build to_2s_complement by individual elements. #264

Merged
merged 2 commits into from
Jun 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 53 additions & 31 deletions logproof/src/linear_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,13 +833,64 @@ impl LogProof {
(r_2, r_1)
}

/**
* Takes an individual values in a field `Zq`, treats the value as signed [q's
* complement](https://en.wikipedia.org/wiki/Method_of_complements) and
* converts the value to binary 2's complement. This is then appended to an
* provided BitVec.
*
* `value` is the element in Zq and `b` is the number of bits needed
* to represent the signed value.
*
* This modifies bitvec in place.
*
*/
fn to_2s_complement_single<Q, const N: usize>(
value: &Fp<MontBackend<Q, N>, N>,
log_b: u64,
bitvec: &mut BitVec,
) where
Q: MontConfig<N>,
{
// Get the value out of Montgomery form.
let value = MontBackend::into_bigint(*value);

let mod_div_2 = Fp::<MontBackend<Q, N>, N>::field_modulus_div_2();
let modulus = Fp::<MontBackend<Q, N>, N>::field_modulus();
let is_negative = value > mod_div_2;

// Compute the q's complement of value
let mut as_neg: BigInt<N> = modulus;
as_neg.sub_with_borrow(&value);

// The smaller of value and it's q's complement is the absolute
// value.
let mut abs_value = BigInt::min(value, as_neg);

// To make a positive number negative in 2's complement,
// subtract 1 and flip the bits. So, here we sub 1 from abs if
// original value was negative.
let big_negative = BigInt::from(is_negative as u8);
abs_value.sub_with_borrow(&big_negative);

for i in 0..(log_b - 1) {
let bit = abs_value.get_bit(i as usize);

// Invert the bit if the original value was negative
bitvec.push(bit ^ is_negative);
}

// Now push the sign bit
bitvec.push(is_negative);
}

/**
* Takes a slice of values in a field `Zq`, treats the values as signed [q's
* complement](https://en.wikipedia.org/wiki/Method_of_complements)
* and converts the value to binary 2's complement.
*
* `value` is the element in Zq and `b` is the number of bits needed
* to represent the
* to represent the signed value.
*/
fn to_2s_complement<Q, const N: usize>(
values: &[Fp<MontBackend<Q, N>, N>],
Expand All @@ -852,36 +903,7 @@ impl LogProof {

// This code should not feature timing side-channels.
for value in values.iter() {
// Get the value out of Montgomery form.
let value = MontBackend::into_bigint(*value);

let mod_div_2 = Fp::<MontBackend<Q, N>, N>::field_modulus_div_2();
let modulus = Fp::<MontBackend<Q, N>, N>::field_modulus();
let is_negative = value > mod_div_2;

// Compute the q's complement of value
let mut as_neg: BigInt<N> = modulus;
as_neg.sub_with_borrow(&value);

// The smaller of value and it's q's complement is the absolute
// value.
let mut abs_value = BigInt::min(value, as_neg);

// To make a positive number negative in 2's complement,
// subtract 1 and flip the bits. So, here we sub 1 from abs if
// original value was negative.
let big_negative = BigInt::from(is_negative as u8);
abs_value.sub_with_borrow(&big_negative);

for i in 0..(log_b - 1) {
let bit = abs_value.get_bit(i as usize);

// Invert the bit if the original value was negative
bitvec.push(bit ^ is_negative);
}

// Now push the sign bit
bitvec.push(is_negative);
LogProof::to_2s_complement_single(value, log_b, &mut bitvec);
}

bitvec
Expand Down