Skip to content

Commit b80452a

Browse files
committed
Merge #320: benches: fix divmod_128_64 distribution
888115c benches: fix divmod128_64 distribution (Andrew Poelstra) Pull request description: The `div_mod_128_64` jet has preconditions and shortcuts its operation if these are not met. To benchmark correctly we need to sample according to those preconditions. ACKs for top commit: canndrew: ACK 888115c Tree-SHA512: a9ddc32def17427bf2f28b4d8d41246bac1b1c71e97e8e3615797bf2e97ed728c5163427bd099a71d57004febebe2c9ba8768e4fe62722077a1f9b55b6e69778
2 parents 81c67e1 + 888115c commit b80452a

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

jets-bench/benches/elements/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use simplicity::types::Final;
1111
use simplicity::Value;
1212
use simplicity_bench::input::{
1313
self, EqProduct, GenericProduct, InputSample, PrefixBit, Sha256Ctx, UniformBits,
14-
UniformBitsExact,
14+
DivMod12864Input,
1515
};
1616
use simplicity_bench::{
1717
genesis_pegin, BenchSample, EnvSampling, InputSampling, JetBuffer, JetParams, SimplicityCtx8,
@@ -508,7 +508,7 @@ fn bench(c: &mut Criterion) {
508508
(Elements::DivMod16, &EqProduct(UniformBits)),
509509
(Elements::DivMod32, &EqProduct(UniformBits)),
510510
(Elements::DivMod64, &EqProduct(UniformBits)),
511-
(Elements::DivMod128_64, &GenericProduct(UniformBitsExact::<128>, UniformBitsExact::<64>)),
511+
(Elements::DivMod128_64, &DivMod12864Input),
512512
// divide
513513
(Elements::Divide8, &EqProduct(UniformBits)),
514514
(Elements::Divide16, &EqProduct(UniformBits)),

jets-bench/src/input.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ impl FlatValue {
282282
}
283283

284284
/// Creates an iterator over the bits of the value
285-
pub fn bit_iter(&self) -> FlatValueBitIter {
285+
pub fn bit_iter(&self) -> FlatValueBitIter<'_> {
286286
FlatValueBitIter {
287287
inner: self,
288288
n_read: 0,
@@ -1322,6 +1322,66 @@ impl InputSampleExactSize for CheckSigSignature {
13221322
}
13231323
}
13241324

1325+
pub struct DivMod12864Input;
1326+
1327+
impl InputSample for DivMod12864Input {
1328+
fn n_distributions(&self) -> usize {
1329+
// divmod128_64 has specific preconditions (unlike the other divmod jets).
1330+
// If these are not met then it does a quick shortcut error return.
1331+
2
1332+
}
1333+
1334+
fn distribution_name(&self, dist: usize) -> String {
1335+
if dist == 0 {
1336+
"uniform".into()
1337+
} else {
1338+
"divmod12864precondition".into()
1339+
}
1340+
}
1341+
1342+
fn sample(&self, dist: usize, n_bits: usize) -> FlatValue {
1343+
assert_eq!(
1344+
n_bits, 192,
1345+
"attempt to sample divmod128_64 input with {} bits (expected 192)",
1346+
n_bits
1347+
);
1348+
1349+
if dist == 0 {
1350+
UniformBits.sample(0, 192)
1351+
} else if dist == 1 {
1352+
// The input to div_mod_128_64 is a 128-bit integer `a` followed by a 64-bit integer `b`.
1353+
// It has two preconditions:
1354+
// 1. The high bit of b must be set.
1355+
// 2. ah (the high 64 bits of a) is strictly less than b.
1356+
//
1357+
// See the implementation of `simplicity_div_mod_128_64` in libsimplicity C/jets.c
1358+
// for how these are implemented.
1359+
1360+
// To implement this, we sample two random 64-bit strings, with one of them
1361+
// having its high bit forced to 1. The higher of the two (which will always
1362+
// have its high bit 1) is b, and the other one is ah.
1363+
let sample_1 = FlatValue::random_n_bits(63).prefix_one();
1364+
let sample_2 = FlatValue::random_n_bits(64);
1365+
for (bit1, bit2) in sample_1.bit_iter().zip(sample_2.bit_iter()) {
1366+
match (bit1, bit2) {
1367+
(false, false) | (true, true) => {} // both equal
1368+
(true, false) => return FlatValue::product(&[sample_2, UniformBits.sample(0, 64), sample_1]),
1369+
(false, true) => return FlatValue::product(&[sample_1, UniformBits.sample(0, 64), sample_2]),
1370+
}
1371+
}
1372+
unreachable!("if we get here, two uniform 63-bit samples were exactly equal")
1373+
} else {
1374+
panic!("invalid distribution {} for div_mod_128_64", dist)
1375+
}
1376+
}
1377+
}
1378+
1379+
impl InputSampleExactSize for DivMod12864Input {
1380+
fn n_bits(&self) -> usize {
1381+
192
1382+
}
1383+
}
1384+
13251385
#[cfg(test)]
13261386
mod tests {
13271387
use super::*;

0 commit comments

Comments
 (0)