Skip to content

Commit

Permalink
hacspec-lib: Bits -> LittleEndianBitStream and added utility function…
Browse files Browse the repository at this point in the history
… to get nth bit given coefficient bit size. (#32)
  • Loading branch information
xvzcf authored Aug 4, 2023
1 parent 622481c commit 7a3d056
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 53 deletions.
75 changes: 43 additions & 32 deletions specs/hacspec-lib/src/bit_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ impl BitVector {
}
}

pub trait Bits {
fn bit(&self, bit: usize) -> u8;
fn iter(&self) -> BitsIter<'_>;
pub trait LittleEndianBitStream {
fn nth_bit(&self, n: usize) -> u8;
fn iter(&self) -> LittleEndianBitStreamIter<'_>;
}

pub struct BitsIter<'a> {
pub struct LittleEndianBitStreamIter<'a> {
bytes: &'a [u8],
bit: usize,
}

impl Iterator for BitsIter<'_> {
impl Iterator for LittleEndianBitStreamIter<'_> {
type Item = u8;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -71,35 +71,35 @@ impl Iterator for BitsIter<'_> {
return None;
}

let out = self.bytes.bit(self.bit);
let out = self.bytes.nth_bit(self.bit);
self.bit += 1;

Some(out)
}
}

impl Bits for &[u8] {
fn bit(&self, bit: usize) -> u8 {
let byte = bit / 8;
let byte_bit = 7 - bit % 8;
impl LittleEndianBitStream for &[u8] {
fn nth_bit(&self, n: usize) -> u8 {
let byte = n / 8;
let byte_bit = n % 8;
(self[byte] >> byte_bit) & 1
}

fn iter(&self) -> BitsIter<'_> {
BitsIter {
fn iter(&self) -> LittleEndianBitStreamIter<'_> {
LittleEndianBitStreamIter {
bytes: self,
bit: 0,
}
}
}

impl Bits for Vec<u8> {
fn bit(&self, bit: usize) -> u8 {
self.as_slice().bit(bit)
impl LittleEndianBitStream for Vec<u8> {
fn nth_bit(&self, n: usize) -> u8 {
self.as_slice().nth_bit(n)
}

fn iter(&self) -> BitsIter<'_> {
BitsIter {
fn iter(&self) -> LittleEndianBitStreamIter<'_> {
LittleEndianBitStreamIter {
bytes: self,
bit: 0,
}
Expand All @@ -108,31 +108,42 @@ impl Bits for Vec<u8> {

#[cfg(test)]
mod tests {
use crate::bit_vector::Bits;
use crate::bit_vector::LittleEndianBitStream;

#[test]
fn bits() {
// 00000001 00000010 00000011 00000100 00000101 00000110 ...
// 1 2 3 4 5 6
let v = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];

let mut bit = 0;
for i in bit..7 {
assert_eq!(v.bit(i), 0);
let mut n = 0;

assert_eq!(v.nth_bit(n), 1);
n += 1;

for n_ in n..8 {
assert_eq!(v.nth_bit(n_), 0);
}
bit += 7;
assert_eq!(v.bit(bit), 1);
bit = 8;
for i in bit..14 {
assert_eq!(v.bit(i), 0);
n = 8;

assert_eq!(v.nth_bit(n), 0);
n += 1;

assert_eq!(v.nth_bit(n), 1);
n += 1;

for n_ in n..16 {
assert_eq!(v.nth_bit(n_), 0);
}
bit = 14;
assert_eq!(v.bit(bit), 1);
bit += 1;
assert_eq!(v.bit(bit), 0);
n = 16;

assert_eq!(v.nth_bit(n), 1);
n += 1;

assert_eq!(v.nth_bit(n), 1);

for bit in v.iter() {
eprint!("{bit}");
for n in v.iter() {
eprint!("{n}");
}
eprintln!();
}
Expand Down
6 changes: 3 additions & 3 deletions specs/hacspec-lib/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub trait FieldElement:
const ZERO: Self;

fn new(number: u16) -> Self;
fn bit(&self, bit: usize) -> u8;
fn nth_bit_little_endian(&self, n: usize) -> u8;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand All @@ -32,8 +32,8 @@ impl<const MODULUS: u16> FieldElement for PrimeFieldElement<MODULUS> {
}
}

fn bit(&self, bit: usize) -> u8 {
((self.value >> bit) & 1) as u8
fn nth_bit_little_endian(&self, n: usize) -> u8 {
((self.value >> n) & 1) as u8
}
}

Expand Down
42 changes: 27 additions & 15 deletions specs/hacspec-lib/src/ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,59 @@ use std::ops::{self, Index, IndexMut};

use crate::field::FieldElement;

pub trait Bits<F: FieldElement, const COEFFICIENTS: usize> {
fn bit(&self, bit: usize) -> u8;
fn bits_iter(&self) -> BitsIter<'_, F, COEFFICIENTS>;
fn bits_chunks(&self, chunk_len: usize) -> BitsIter<'_, F, COEFFICIENTS>;
pub trait LittleEndianBitStream<F: FieldElement, const COEFFICIENTS: usize> {
fn nth_bit(&self, n: usize) -> u8;
fn nth_bit_with_coefficient_bit_size(&self, n: usize, coefficient_bit_size: usize) -> u8;
fn bits_iter(&self) -> LittleEndianBitStreamIter<'_, F, COEFFICIENTS>;
fn bits_chunks(&self, chunk_len: usize) -> LittleEndianBitStreamIter<'_, F, COEFFICIENTS>;
}

pub struct BitsIter<'a, F: FieldElement, const COEFFICIENTS: usize> {
pub struct LittleEndianBitStreamIter<'a, F: FieldElement, const COEFFICIENTS: usize> {
values: &'a [F; COEFFICIENTS],
bit: usize,
chunk_len: usize,
}

impl<F: FieldElement, const COEFFICIENTS: usize> Bits<F, COEFFICIENTS> for &[F; COEFFICIENTS] {
fn bit(&self, bit: usize) -> u8 {
let index = bit / 16;
let bit_mod = bit % 16;
impl<F: FieldElement, const COEFFICIENTS: usize> LittleEndianBitStream<F, COEFFICIENTS>
for &[F; COEFFICIENTS]
{
fn nth_bit(&self, n: usize) -> u8 {
let index = n / 16;
let bit_mod = n % 16;
// eprintln!(" >>> self[{index}] >> {bit_mod}");
((Into::<u16>::into(self[index]) >> bit_mod) & 1) as u8
}

fn bits_iter(&self) -> BitsIter<'_, F, COEFFICIENTS> {
BitsIter {
fn nth_bit_with_coefficient_bit_size(&self, n: usize, coefficient_bit_size: usize) -> u8 {
let coefficient_index = n / coefficient_bit_size;
let coefficient_bit = n % coefficient_bit_size;

self[coefficient_index].nth_bit_little_endian(coefficient_bit)
}

fn bits_iter(&self) -> LittleEndianBitStreamIter<'_, F, COEFFICIENTS> {
LittleEndianBitStreamIter {
values: self,
bit: 0,
chunk_len: 1,
}
}

fn bits_chunks(&self, chunk_len: usize) -> BitsIter<'_, F, COEFFICIENTS> {
fn bits_chunks(&self, chunk_len: usize) -> LittleEndianBitStreamIter<'_, F, COEFFICIENTS> {
// This iterator allows setting the number of bits used to encode one limb.
// It is NOT chunking.
assert!(chunk_len <= 16);
BitsIter {
LittleEndianBitStreamIter {
values: self,
bit: 0,
chunk_len,
}
}
}

impl<F: FieldElement, const COEFFICIENTS: usize> Iterator for BitsIter<'_, F, COEFFICIENTS> {
impl<F: FieldElement, const COEFFICIENTS: usize> Iterator
for LittleEndianBitStreamIter<'_, F, COEFFICIENTS>
{
type Item = Vec<u8>;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -59,7 +71,7 @@ impl<F: FieldElement, const COEFFICIENTS: usize> Iterator for BitsIter<'_, F, CO
// self.bit / 16
// );
for i in 0..self.chunk_len {
out[i] = self.values.bit(self.bit + i);
out[i] = self.values.nth_bit(self.bit + i);
}
self.bit += 16;

Expand Down
2 changes: 1 addition & 1 deletion specs/kyber/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ hacspec-lib = { version = "0.0.1", path = "../hacspec-lib" }
[dev-dependencies]
criterion = "0.5.1"
hex = { version = "0.4.3", features = ["serde"] }
pqcrypto = "0.16.1"
pqcrypto-kyber = { version = "0.7.6", default-features = false }
proptest = "1.2.0"
rand = "0.8.5"
serde = { version = "1.0.171", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion specs/kyber/benches/kem.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};

use pqcrypto::kem::kyber768;
use pqcrypto_kyber::kyber768;

use rand;

Expand Down
2 changes: 1 addition & 1 deletion specs/kyber/src/serialize.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use hacspec_lib::{bit_vector::BitVector, ring::Bits};
use hacspec_lib::{bit_vector::BitVector, ring::LittleEndianBitStream};

use crate::parameters::{KyberFieldElement, KyberPolynomialRingElement, BITS_PER_COEFFICIENT};

Expand Down

0 comments on commit 7a3d056

Please sign in to comment.