crypto-ratio 0.1.0

Rational number arithmetic using crypto-bigint
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# crypto-ratio

[![Crates.io](https://img.shields.io/crates/v/crypto-ratio.svg)](https://crates.io/crates/crypto-ratio)
[![Documentation](https://docs.rs/crypto-ratio/badge.svg)](https://docs.rs/crypto-ratio)
[![License](https://img.shields.io/crates/l/crypto-ratio.svg)](LICENSE)

Rational number arithmetic using crypto-bigint [crypto-bigint](https://github.com/RustCrypto/crypto-bigint).

Built for use in [RISC Zero](https://risczero.com) zkVM applications to leverage accelerated crypto-bigint precompiles with rational number operations.

## Features

- **Generic over integer width**: Works with U64, U256, U512, U1024, U2048, and all crypto-bigint types up to U16384 
- **RISC Zero optimized**: Designed to work with [RISC Zero's accelerated crypto-bigint precompiles]https://dev.risczero.com/api/zkvm/accelerators
- **Performance-focused**: Deferred reduction and smart heuristics minimize expensive GCD operations
- **Overflow handling**: Automatic fallback to wider types when operations overflow 
- **no_std compatible**: Works in embedded, constrained, and zkVM environments

## Why RISC Zero?

This library was built to enable efficient rational number arithmetic in RISC Zero's zkVM, where [crypto-bigint operations are hardware-accelerated](https://dev.risczero.com/api/zkvm/precompiles) through precompiles. By building on crypto-bigint rather than num-bigint, this crate can leverage:

- **Hardware acceleration** for big integer operations in zkVM
- **Reduced cycle counts** for cryptographic workloads (U256 and U512 extrem fast)

Special thanks to the [RISC Zero team](https://risczero.com) for building an incredible zkVM platform and for their excellent documentation on accelerator usage.

## Installation

Add to your `Cargo.toml`:
```toml
[dependencies]
crypto-ratio = "0.1"
crypto-bigint = "0.5"
```

For RISC Zero zkVM guests:
```toml
[dependencies]
crypto-ratio = "0.1"
crypto-bigint = "0.5"
risc0-zkvm = { version = "3.0.3" }
```

## Quick Start
```rust
use crypto_ratio::{Ratio, RatioU512};
use crypto_bigint::U512;

// Create rationals
let a = RatioU512::from_u64(1, 2);  // 1/2
let b = RatioU512::from_u64(1, 3);  // 1/3

// Arithmetic operations
let sum = &a + &b;  // 5/6
let product = &a * &b;  // 1/6

// Explicit reduction when needed
let mut result = product;
result.normalize();

// Comparison
assert!(a > b);

// Float conversion
let r = RatioU512::from_float(0.75).unwrap();
assert_eq!(r.to_f64_approx(), 0.75);
```

## RISC Zero zkVM Example
```rust
use crypto_ratio::RatioU512;
use risc0_zkvm::guest::env;

pub fn main() {
    // Read inputs from host
    let a_numer: u64 = env::read();
    let a_denom: u64 = env::read();
    let b_numer: u64 = env::read();
    let b_denom: u64 = env::read();
    
    // Perform rational arithmetic (leverages crypto-bigint precompiles)
    let a = RatioU512::from_u64(a_numer, a_denom);
    let b = RatioU512::from_u64(b_numer, b_denom);
    
    let mut result = a.mul(&b);
    result.normalize();
    
    // Commit result
    env::commit(&result.numer.to_le_bytes());
    env::commit(&result.denom.to_le_bytes());
}
```

## Design Philosophy

### Unreduced Operations by Default

Operations like multiplication and addition return **unreduced** results for performance. Call `normalize()` explicitly when reduction is needed:
```rust
use crypto_ratio::RatioU256;

let a = RatioU256::from_u64(2, 3);
let b = RatioU256::from_u64(3, 4);

// Unreduced: 6/12
let product = &a * &b;

// Reduced: 1/2
let mut reduced = product;
reduced.normalize();
```

**Why?** In loops and chained operations, automatic reduction uses too much cycles:
```rust
// Bad: Reduces 100 times (expensive!)
let mut sum = RatioU512::zero();
for i in 0..100 {
    let term = RatioU512::from_u64(i, 1000);
    sum = sum + term;  // Auto-reduce would GCD here
}

// Good: Reduces once at the end
let mut sum = RatioU512::zero();
for i in 0..100 {
    let term = RatioU512::from_u64(i, 1000);
    sum = sum.add(&term);  // Unreduced
}
sum.normalize();  // Single GCD at the end
```

### Smart Reduction Heuristics

`mul_reduced()` provides automatic reduction using fast heuristics:
```rust
let a = RatioU512::from_u64(2, 3);
let b = RatioU512::from_u64(3, 4);

// Smart reduction uses:
// 1. Bit shifts for power-of-2 factors (~10ns)
// 2. Fast u64 GCD for small values (~50ns)
// 3. Skips GCD for large coprime values (~0ns)
let product = a.mul_reduced(&b);  // 1/2 (reduced)
```

### Generic Over Integer Width

Choose the size that fits your precision and performance needs:
Heads up: Performance decreases from U2048 onwards due to automatic wide types on overflow, fix coming soon. 
```rust
use crypto_ratio::{Ratio, RatioU256, RatioU512, RatioU1024};
use crypto_bigint::{U256, U512, U1024};

// Small: Fast operations, limited range
let small = RatioU256::from_u64(1, 2);

// Medium: Good balance (recommended)
let medium = RatioU512::from_u64(1, 2);

// Large: Maximum precision
let large = RatioU1024::from_u64(1, 2);

// Custom size
let custom = Ratio::<U256>::from_u64(1, 2);
```

### Overflow Handling

Operations automatically use wider types when needed:
```rust
use crypto_ratio::RatioU256;

// U256 operations may internally use U512
let a = RatioU256::from_u64(u64::MAX, 1);
let b = RatioU256::from_u64(u64::MAX, 1);

// This works! Uses U512 internally, reduces back to U256
let sum = a.add(&b);
```

## Real-World Example: Taylor Series

Computing e^x using Taylor series expansion demonstrates the performance benefits:
```rust
use crypto_ratio::RatioU512;
use crypto_bigint::U512;

fn exp_approx(x: RatioU512, terms: usize) -> RatioU512 {
    let mut result = RatioU512::one();
    let mut term = RatioU512::one();
    let mut factorial = U512::ONE;
    
    for n in 1..terms {
        factorial = factorial.wrapping_mul(&U512::from_u64(n as u64));
        term = term.mul(&x);
        
        let next_term = term.div_by_uint(&factorial);
        result = result.add(&next_term);
        
        // Only reduce when needed (heuristic-based)
        if result.needs_reduction() {
            result.normalize();
        }
    }
    
    result.normalize();
    result
}

let x = RatioU512::from_float(0.5).unwrap();
let e_to_half = exp_approx(x, 10);
println!("e^0.5 ≈ {}", e_to_half.to_f64_approx());
```

## Trade-offs

### Performance vs Automatic Reduction

| Approach | Pros | Cons | Best For |
|----------|------|------|----------|
| Unreduced (default) | 10-100x faster in loops | Manual `normalize()` calls | High-performance code, loops, zkVM |
| `mul_reduced()` | Smart, usually fast | Some overhead | General use, single operations |
| Always reduce | Simple API | Much slower | Prototyping |

### Integer Size Selection

| Size | Range | Speed | Memory | Use Case |
|------|-------|-------|--------|----------|
| U256 | ~77 decimal digits | Fastest | 32 bytes | Embedded, simple fractions, zkVM-optimized |
| U512 | ~154 decimal digits | Fast | 64 bytes | Embedded, zkVM-optimized **Recommended default** |
| U1024 | ~308 decimal digits | Moderate | 128 bytes | High precision |
| U2048+ | ~600+ decimal digits | Slower | 256+ bytes | Specialized applications (performance drops, num-bigint might be faster) |

## Performance

### Benchmark Overview

Typical performance on modern hardware (U512):

| Operation | Time | Speedup vs num-rational |
|-----------|------|-------------------------|
| Construction | ~15ns | 2-3x faster |
| Addition | ~30ns | 5-10x faster |
| Multiplication (unreduced) | ~25ns | 10-20x faster |
| Multiplication (reduced) | ~80ns | 3-5x faster |
| Comparison | ~35ns | 3-5x faster |
| GCD | ~200ns | 2-3x faster |
| Taylor Series (5 terms) | ~800ns | 8-12x faster |

## Running Tests
```bash
# Run all tests (2,300+ tests across 9 integer sizes)
cargo test

# Run tests for specific size
cargo test u256_tests
cargo test u512_tests

# Run specific test
cargo test test_addition_compatibility

# Run with output
cargo test -- --nocapture

# Run tests with all features
cargo test --all-features
```

## Running Benchmarks
```bash
# Run all benchmarks
cargo bench

# Run benchmarks for specific size
cargo bench U256
cargo bench U512

# Run specific operation
cargo bench multiplication
cargo bench taylor_series

# Run specific size + operation
cargo bench U512/multiplication

# Generate detailed report with violin plots
cargo bench -- --save-baseline main

# Compare against baseline
cargo bench -- --baseline main
```

Benchmark results are saved in `target/criterion/` with detailed HTML reports including:
- Violin plots showing distribution
- Regression analysis
- Historical comparison
- Statistical significance tests

### Viewing Benchmark Reports

After running benchmarks, open the HTML report:
```bash
# On macOS
open target/criterion/report/index.html

# On Linux
xdg-open target/criterion/report/index.html

# On Windows
start target/criterion/report/index.html
```

## API Overview

### Construction
```rust
// From u64 (with reduction)
let r = RatioU512::from_u64(2, 3);

// From float
let r = RatioU512::from_float(0.5).unwrap();

// Without reduction
let r = RatioU512::new_raw(numer, denom, false);

// With reduction
let r = RatioU512::new(numer, denom);
```

### Arithmetic
```rust
let a = RatioU512::from_u64(1, 2);
let b = RatioU512::from_u64(1, 3);

// Basic operations (unreduced)
let sum = &a + &b;
let diff = &a - &b;
let prod = &a * &b;
let quot = &a / &b;

// Negation
let neg = -a;

// Reciprocal
let recip = a.recip();
```

### Reduction
```rust
let mut r = RatioU512::from_u64(6, 8);

// Explicit reduction
r.normalize();  // Now 3/4

// Conditional reduction
if r.needs_reduction() {
    r.normalize();
}

// Smart multiplication
let a = RatioU512::from_u64(2, 3);
let b = RatioU512::from_u64(3, 4);
let prod = a.mul_reduced(&b);  // 1/2 (reduced)
```

### Comparison
```rust
let a = RatioU512::from_u64(1, 2);
let b = RatioU512::from_u64(1, 3);

assert!(a > b);
assert!(a >= b);
assert!(b < a);
assert!(a != b);
```

## no_std Support

This crate is `no_std` compatible (requires `alloc` for GCD operations):
```toml
[dependencies]
crypto-ratio = { version = "0.1", default-features = false }
```

Perfect for:
- Embedded systems
- RISC Zero zkVM guests
- WebAssembly
- Constrained environments

## Minimum Supported Rust Version (MSRV)

Rust 1.65 or later.

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Run `cargo test` and `cargo bench`
5. Ensure `cargo clippy` passes
6. Submit a pull request

## Comparison with Alternatives

| Feature | crypto-ratio | num-rational | rug |
|---------|--------------|--------------|-----|
| Pure Rust ||| ❌ (GMP) |
| no_std ||||
| RISC Zero zkVM ||||
| Generic width ||||
| Deferred reduction ||||
| Compile-time size ||||
| Accelerated precompiles ||||
| Performance | High | Medium | Very High* |

*GMP performance only available in native code, not in zkVM environments.

**Choose crypto-ratio if you need**: RISC Zero zkVM support, pure Rust, no_std support, control over reduction, or compile-time size selection.

**Choose num-rational if you need**: Simple API with automatic reduction, dynamic sizing, don't need zkVM support.

**Choose rug if you need**: Maximum performance in native environments, don't mind GMP dependency.

## Acknowledgments

Built on [crypto-bigint](https://github.com/RustCrypto/crypto-bigint) by RustCrypto.

Designed for [RISC Zero](https://risczero.com) zkVM with support for hardware-accelerated big integer operations.

Inspired by [num-rational](https://github.com/rust-num/num-rational) with focus on stable performance and flexibility.

## Resources

- [RISC Zero Documentation]https://dev.risczero.com
- [crypto-bigint Accelerators in RISC Zero]https://dev.risczero.com/api/zkvm/precompiles
- [API Documentation]https://docs.rs/crypto-ratio

---

**Questions?** Open an issue or discussion on [GitHub](https://github.com/sbcdn/crypto-ratio).