This commit is contained in:
Your Name
2025-04-20 19:16:03 -04:00
commit dfed917799
10 changed files with 665 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
Generated
+288
View File
@@ -0,0 +1,288 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "apet_ex1"
version = "0.1.0"
dependencies = [
"curve25519-dalek",
"num-bigint",
"num-traits",
"rand",
"rand_core 0.4.2",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "4.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest",
"fiat-crypto",
"rand_core 0.6.4",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"crypto-common",
]
[[package]]
name = "fiat-crypto"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "apet_ex1"
version = "0.1.0"
edition = "2024"
[features]
stdout=[]
[dependencies]
curve25519-dalek = { version = "4.1.3", features = ["rand_core", "digest"] }
rand = "0.8.5"
rand_core = "0.4"
num-bigint = "0.4"
num-traits = "0.2"
+149
View File
@@ -0,0 +1,149 @@
use std::collections::HashMap;
use crate::{gate::Gate, gate_type::GateType};
#[derive(Debug, Clone)]
pub struct Circuit {
pub input_bits: Vec<bool>, // Input wires
pub gates: Vec<Gate>, // All gates
}
impl Circuit {
pub fn eval(self) -> bool {
let mut evaluated_gates = vec!();
for gate in self.gates {
let result = gate.eval(&self.input_bits, &evaluated_gates);
evaluated_gates.push(result);
}
match evaluated_gates.pop() {
Some(result) => result,
None => panic!("Bruh moment")
}
}
/*
This method should create a circuit that outputs 1 if the first number A (encoded in the first n
bits) is greater than the second number B (encoded in the next n bits) .
*/
pub fn compare_n_bit_numbers(input_bits: Vec<bool>, n: usize) -> Self {
if input_bits.len() < 2*n {
panic!("Expected input_bits to be of at least length {}, but it was {}", 2*n, input_bits.len())
}
/*
base case n=1: 1-bit:
A B | A > B
-----------
0 0 | 0
0 1 | 0
1 0 | 1
1 1 | 0
n+1 case: 2-bit:
A1 A0 B1 B0 | A > B | (A1 > B1) || ((A1 == B1) && (A0 > B0))
----------------------|------------------------------------
0 0 0 0 | 0 | 0
0 0 0 1 | 0 | 0
0 0 1 0 | 0 | 0
0 0 1 1 | 0 | 0
0 1 0 0 | 1 | 1
0 1 0 1 | 0 | 0
0 1 1 0 | 0 | 0
0 1 1 1 | 1 | 1
1 0 0 0 | 1 | 1
1 0 0 1 | 1 | 1
1 0 1 0 | 0 | 0
1 0 1 1 | 0 | 0
1 1 0 0 | 1 | 1
1 1 0 1 | 1 | 1
1 1 1 0 | 1 | 1
1 1 1 1 | 0 | 0
The inductive pattern should become apparent now.
For illustration here's the case for n=4, which should show the
recursive characteristics of the formula.
(A3 > B3) ||
((A3 == B3) && (A2 > B2)) ||
((A3 == B3) && (A2 == B2) && (A1 > B1)) ||
((A3 == B3) && (A2 == B2) && (A1 == B1)) && (A0 > B0))
*/
let gates = create_n_bit_comparator_gates(n);
return Circuit { input_bits, gates }
}
}
fn create_n_bit_comparator_gates(n: usize) -> Vec<Gate>{
let mut indices = HashMap::<String, usize>::new();
let mut all_gates: Vec<Gate> = vec!();
let mut and_gate_indices: Vec<usize> = vec!();
rec_n_bit_comperator_gates(0, n, &mut all_gates, &mut and_gate_indices, &mut indices, );
// the OR spanning all ANDs
let or_gate = Gate::new( GateType::Or, and_gate_indices, vec!());
all_gates.push(or_gate);
return all_gates;
}
fn rec_n_bit_comperator_gates(curr: usize, max: usize, all_gates: &mut Vec<Gate>, and_gate_incides: &mut Vec<usize>, indices: &mut HashMap<String, usize>){
// Incrementing gate index
let a_curr_gt_b_curr_gate_index = all_gates.len();
// Gate(A_current > B_current)
let a_curr_gt_b_curr_gate = Gate::new(GateType::Bigger, vec!(), vec!(curr, curr+max));
// A_current>B_current
//print!(" ( ({}) ", format!("{} > {}", format!("A{}", max-1-curr), format!("B{}", max-1-curr)));
all_gates.push(a_curr_gt_b_curr_gate);
let mut this_recursion_gate_indices: Vec<usize> = vec!(a_curr_gt_b_curr_gate_index);
for i in 0..curr {
// A_i
let a_i = format!("A{}", max-1-i);
//B_i
let b_i = format!("B{}", max-1-i);
// A_i=B_i
let a_i_eq_b_i = format!("{} = {}", a_i, b_i);
// The curr-1'th equality gate is the only one that doesn't exist yet
if i == curr-1 {
// Gate(A_current > B_current)
let a_i_eq_b_i_gate = Gate::new(GateType::Equal, vec!(), vec!(i, i+max));
let a_curr_gt_b_curr_gate_index = all_gates.len();
indices.insert(a_i_eq_b_i.clone(), a_curr_gt_b_curr_gate_index);
all_gates.push(a_i_eq_b_i_gate);
}
let eq_gate_index = indices.get(&a_i_eq_b_i).unwrap();
//print!("&& ({}) ", a_i_eq_b_i);
// Index of this equality gate
this_recursion_gate_indices.push(*eq_gate_index);
}
let and_curr_index = all_gates.len();
let and_curr_gate = Gate::new(GateType::And, this_recursion_gate_indices, vec!());
all_gates.push(and_curr_gate);
and_gate_incides.push(and_curr_index);
if curr+1 == max {
//println!(")");
return;
}
//println!(") ||");
return rec_n_bit_comperator_gates(curr+1, max, all_gates, and_gate_incides, indices);
}
+122
View File
@@ -0,0 +1,122 @@
use crate::gate_type::GateType;
#[derive(Debug, Clone)]
pub struct Gate {
pub gate_type: GateType,
pub input_gates_indices: Vec<usize>, // Which previous gates to use
pub input_bits_indices: Vec<usize>, // Which input bits to use
}
impl Gate {
pub fn new(
gate_type: GateType,
input_gates_indices: Vec<usize>,
input_bits_indices: Vec<usize>,
) -> Self {
let num_input_wires = input_bits_indices.len() + input_gates_indices.len();
if num_input_wires == 0 {
panic!("A gate without inputs is invalid");
}
if gate_type == GateType::Bigger && num_input_wires != 2 {
if num_input_wires != 2 {
panic!("Bigger gates need exactly two inputs")
}
}
if gate_type == GateType::Equal && num_input_wires != 2 {
if num_input_wires != 2 {
panic!("Equal gates need exactly two inputs")
}
}
Self {
gate_type,
input_gates_indices,
input_bits_indices,
}
}
pub fn eval(&self, input_bits: &Vec<bool>, evaluated_gates: &Vec<bool>) -> bool {
/*
The goal is to perform short-circuit evaluation with the minimum number of vector lookups.
*/
match self.gate_type {
/*
A multi-input gate that outputs 1 if all input bits are 1, and 0 otherwise
*/
GateType::And => {
for &index in self.input_bits_indices.iter(){
if !input_bits[index] {
return false;
}
}
for &index in self.input_gates_indices.iter(){
if !evaluated_gates[index] {
return false;
}
}
return true;
}
/*
A multi-input gate that outputs 1 if at least one input bit is 1, and 0 otherwise.
*/
GateType::Or => {
for &index in self.input_bits_indices.iter(){
if input_bits[index] {
return true;
}
}
for &index in self.input_gates_indices.iter(){
if evaluated_gates[index] {
return true;
}
}
return false;
},
/*
A gate with exactly two inputs. It outputs 1 if the two input bits are equal
(i.e., both 0 or both 1), and 0 otherwise
*/
GateType::Equal => match self.input_bits_indices.len() {
0 => evaluated_gates[self.input_gates_indices[0]] == evaluated_gates[self.input_gates_indices[1]],
1 => input_bits[self.input_bits_indices[0]] == evaluated_gates[self.input_gates_indices[0]],
2 => {
input_bits[self.input_bits_indices[0]] == input_bits[self.input_bits_indices[1]]
},
_ => panic!{"How'd we get here?"}
},
/*
A gate with exactly two inputs. It outputs 1 if the first input is 1 and the second
input is 0; otherwise, it outputs 0. This gate is used to compare individual bits a_i > b_i
A B | A > B | A && !B
--------------------
0 0 | 0 | 0 0 1
0 1 | 0 | 0 0 0
1 0 | 1 | 1 1 1
1 1 | 0 | 1 0 0
*/
GateType::Bigger => match self.input_bits_indices.len() {
// bits: [] gates: [A,B]
0 => evaluated_gates[self.input_gates_indices[0]] && !evaluated_gates[self.input_gates_indices[1]],
// bits: [A] gates: [B]
1 => input_bits[self.input_bits_indices[0]] && !evaluated_gates[self.input_gates_indices[0]],
// bits: [A,B] gates: []
2 => {
input_bits[self.input_bits_indices[0]] && !input_bits[self.input_bits_indices[1]]
},
_ => panic!{"How'd we get here? {}", input_bits.len()}
},
}
}
}
+7
View File
@@ -0,0 +1,7 @@
#[derive(Debug, Clone, PartialEq)]
pub enum GateType {
And, // multi-input
Or, // multi-input
Equal, // 2-input
Bigger, // 2-input (A > B)
}
+4
View File
@@ -0,0 +1,4 @@
pub mod circuit;
pub mod gate;
pub mod gate_type;
pub mod scalar_to_bits;
+26
View File
@@ -0,0 +1,26 @@
use apet_ex1::{circuit::Circuit, scalar_to_bits::scalar_to_bits};
use curve25519_dalek::Scalar;
use num_bigint::BigUint;
use rand::rngs::OsRng;
fn main() {
let a = Scalar::random(&mut OsRng);
let b = Scalar::random(&mut OsRng);
// Convert to bit representation
let a_bits = scalar_to_bits(&a);
let b_bits = scalar_to_bits(&b);
// Combine A and B bits into one input vector
let mut input_bits = Vec::with_capacity(512);
input_bits.extend_from_slice(&a_bits);
input_bits.extend_from_slice(&b_bits);
// Build and evaluate the comparison circuit
let circuit = Circuit::compare_n_bit_numbers(input_bits, 256);
let circuit_result = circuit.eval();
let a_int = BigUint::from_bytes_le(&a.to_bytes());
let b_int = BigUint::from_bytes_le(&b.to_bytes());
println!("{}", circuit_result == (a_int > b_int))
}
+16
View File
@@ -0,0 +1,16 @@
use curve25519_dalek::Scalar;
pub fn scalar_to_bits(scalar: &Scalar) -> Vec<bool> {
let bytes = scalar.to_bytes();
let mut bits = Vec::with_capacity(256);
// MSB first
for &byte in bytes.iter().rev() {
for i in (0..8).rev() {
let bit = (byte >> i) & 1;
bits.push(bit != 0);
}
}
bits
}
+38
View File
@@ -0,0 +1,38 @@
#[cfg(test)]
mod tests {
use apet_ex1::{circuit::Circuit, scalar_to_bits::scalar_to_bits};
use curve25519_dalek::scalar::Scalar;
use num_bigint::BigUint;
use rand::rngs::OsRng;
#[test]
fn test_scalar_comparison_via_circuit() {
for _ in 0..100 {
let a = Scalar::random(&mut OsRng);
let b = Scalar::random(&mut OsRng);
// Convert to bit representation
let a_bits = scalar_to_bits(&a);
let b_bits = scalar_to_bits(&b);
// Combine A and B bits into one input vector
let mut input_bits = Vec::with_capacity(512);
input_bits.extend_from_slice(&a_bits);
input_bits.extend_from_slice(&b_bits);
// Build and evaluate the comparison circuit
let circuit = Circuit::compare_n_bit_numbers(input_bits, 256);
let circuit_result = circuit.eval();
// Compare expected result using BigUint
let a_int = BigUint::from_bytes_le(&a.to_bytes());
let b_int = BigUint::from_bytes_le(&b.to_bytes());
let expected = a_int > b_int;
assert_eq!(
circuit_result, expected,
"Mismatch: A = {:?}, B = {:?}, A > B = {}, but circuit says {}",
a_int, b_int, expected, circuit_result
);
}
}
}