command line, read numbers from file + python script generate test values

This commit is contained in:
Sam Hadow 2025-04-11 09:12:18 +02:00
parent 950b64c4cd
commit 64c58265c4
5 changed files with 119 additions and 34 deletions

View File

@ -6,5 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.5.35", features = ["derive"] }
lll-rs = "0.2.0"
rug = "1.27.0"

View File

@ -1,6 +1,28 @@
from random import randint
p = randint(100,1000)
a = ["Integer::from("+str(p*randint(1,100)+randint(0,20))+"), " for _ in range(200)]
for b in a:
print(b)
print(p)
import sys
import random
import argparse
def generate_test_file(noise_bits, number):
p = random.randint(100, 1000)
while p % 2 == 0:
p = random.randint(100, 1000)
max_noise = (1 << noise_bits) - 1 # 2^noise_bits - 1
a = [str(p * random.randint(1, 100) + random.randint(0, max_noise)) for _ in range(number)]
print(noise_bits)
for b in a:
print(b)
print(f"// True p: {p}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generate test input for AGCD computation')
parser.add_argument('--noise-bits', type=int, default=5, help='Number of noise bits (default: 5)')
parser.add_argument('--number', type=int, default=20, help='Number of numbers to generate (default: 20)')
args = parser.parse_args()
generate_test_file(args.noise_bits, args.number)

View File

@ -1,7 +1,7 @@
use rug::Integer;
use crate::matrix::Matrix;
use crate::utils::abs;
use lll_rs::l2::bigl2;
use rug::Integer;
pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize) -> Integer {
// 1. Build lattice matrix basis

52
src/file.rs Normal file
View File

@ -0,0 +1,52 @@
use std::fs;
use std::path::Path;
use rug::Integer;
use std::io;
pub struct AgcdInput {
pub noise_bits: usize,
pub numbers: Vec<Integer>,
}
// Parse the input file, return noise_bits and numbers.
pub fn parse_file(path: &Path) -> io::Result<AgcdInput> {
let content = fs::read_to_string(path)?;
let mut lines = content.lines();
// Parse noise_bits from first non comment line
let noise_bits = loop {
match lines.next() {
Some(first_line) => {
let trimmed = first_line.trim();
if trimmed.starts_with("//") {
continue; // Skip comment lines
}
break trimmed.parse::<usize>()
.map_err(|e| io::Error::new(
io::ErrorKind::InvalidData,
format!("First non-comment line must be noise_bits (usize): {}", e)
))?;
},
None => return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Input file is empty or contains only comments"
)),
}
};
// Parse numbers from remaining lines
let numbers: Vec<Integer> = lines
.filter(|line| !line.trim().starts_with("//") && !line.trim().is_empty()) // ignore comment and empty lines
.filter_map(|line| line.trim().parse::<u64>().ok())
.map(Integer::from)
.collect();
if numbers.len() < 2 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Need at least 2 numbers to compute AGCD"
));
}
Ok(AgcdInput { noise_bits, numbers })
}

View File

@ -1,32 +1,42 @@
use rug::Integer;
mod agcd;
mod lll;
mod matrix;
mod utils;
mod agcd;
use crate::agcd::agcd;
mod file;
fn main() {
// 1. Build lattice matrix basis
let ciphertexts = vec![
Integer::from(32219),
Integer::from(21254),
Integer::from(16764),
Integer::from(338),
Integer::from(29960),
Integer::from(23516),
Integer::from(7084),
Integer::from(26735),
Integer::from(23195),
Integer::from(11928),
Integer::from(985),
Integer::from(11916),
Integer::from(13217),
Integer::from(29966),
Integer::from(14171),
Integer::from(13211),
Integer::from(23514),
Integer::from(19643)
];
let noise_bits = 2;
let _ = agcd(ciphertexts, noise_bits);
use crate::agcd::agcd;
use crate::file::parse_file;
use clap::{Parser, Subcommand};
use std::path::{Path, PathBuf};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// approximate GCD
Agcd {
/// (default './input.txt')
path: Option<PathBuf>,
},
}
fn main() -> std::io::Result<()> {
let cli = Cli::parse();
match &cli.command {
Commands::Agcd { path } => {
let path = path.as_deref().unwrap_or(Path::new("./input.txt"));
let input = parse_file(path)?;
let result = agcd(input.numbers, input.noise_bits);
println!("Approximate GCD with noise_bits={}: {}", input.noise_bits, result);
}
}
Ok(())
}