Skip to content

Commit 62278bc

Browse files
committed
Merge #269: Followups to #266 -- more Value optimizations
de20a3b value: inline single-use private from_bits function (Andrew Poelstra) e025850 value: shortcut pruning when the types are the same (Andrew Poelstra) 843fb2b value: speed up zero (Andrew Poelstra) c22b67d value: use `has_padding` to speed up `from_compact_bits` (Andrew Poelstra) d807968 types: add `has_padding` marker to `Final` (Andrew Poelstra) 0072917 value: remove now-unused Padding trait (Andrew Poelstra) 09cdded value: implement padded bit decoding directly (Andrew Poelstra) 57da572 value: promote ValueRef to public type, use it for recursion (Andrew Poelstra) 4d4dce7 value: rename internal `as_value` function to `as_ref` (Andrew Poelstra) dcb2e81 value: add benchmark for giant product of 2^512 x 2^256 (Andrew Poelstra) b7a5ff9 rename POWERS_OF_TWO across the codebase to TWO_TWO_N (Andrew Poelstra) Pull request description: This cleans up the `Value` API by making `ValueRef` public and using it in place of the slow and redundant `Value::to_*` methods. It also renames `Tmr::POWERS_OF_TWO` which was noticed as a confusing name. It adds a `types::Final::has_padding` accessor and uses it to dramatically speed up bit decoding for values. During pruning, it notices when there is nothing to do (when pruning a value to the type that it already has) and shortcuts. Unlike #266, this one leaves the API in better shape than it was before, and should be reasonably easy to review. It hsa a lot of commits but they are all pretty small. Fixes #268 ACKs for top commit: uncomputable: ACK de20a3b Tree-SHA512: ee373e712e086ed5691fdb0c313b6ae4e2c39fc0ba5ebd1388537883734bd34674ede9ae669f291324ee42fff45a701e010a7fda4cb35c0feec57b7a1a85a8c4
2 parents 7da0f37 + de20a3b commit 62278bc

File tree

6 files changed

+194
-250
lines changed

6 files changed

+194
-250
lines changed

src/merkle/cmr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl Cmr {
121121
let imr_iv = Self::CONST_WORD_IV;
122122
let imr_pass1 = imr_iv.update_1(cmr_stack[0]);
123123
// 2. Add TMRs to get the pass-two IMR
124-
let imr_pass2 = imr_pass1.update(Tmr::unit().into(), Tmr::POWERS_OF_TWO[w - 1].into());
124+
let imr_pass2 = imr_pass1.update(Tmr::unit().into(), Tmr::TWO_TWO_N[w - 1].into());
125125
// 3. Convert to a jet CMR
126126
Cmr(bip340_iv(b"Simplicity\x1fJet")).update_with_weight(word.len() as u64, imr_pass2)
127127
}

src/merkle/tmr.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl Tmr {
4141

4242
/// The TMRs of the types TWO^(2^n) for small values of n
4343
#[rustfmt::skip]
44-
pub const POWERS_OF_TWO: [Tmr; 32] = [
44+
pub const TWO_TWO_N: [Tmr; 32] = [
4545
Tmr(Midstate([
4646
0x88, 0x5a, 0x22, 0xde, 0x3e, 0xdb, 0x3f, 0x40,
4747
0xdb, 0x06, 0x09, 0xc2, 0x40, 0x23, 0x30, 0x3f,
@@ -305,14 +305,14 @@ mod tests {
305305
assert_eq!(target, expected_tmrs[i], "mismatch on TMR for TWO^(2^{i})");
306306
}
307307

308-
let n = Tmr::POWERS_OF_TWO.len();
308+
let n = Tmr::TWO_TWO_N.len();
309309
let tmrs = types::Type::powers_of_two(&types::Context::new(), n)
310310
.iter()
311311
.filter_map(types::Type::tmr)
312312
.collect::<Vec<Tmr>>();
313313
debug_assert_eq!(tmrs.len(), n);
314314
for i in 0..n {
315-
check_pow(Tmr::POWERS_OF_TWO[i], i, &tmrs);
315+
check_pow(Tmr::TWO_TWO_N[i], i, &tmrs);
316316
}
317317
}
318318
}

src/node/mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,17 @@ pub trait CoreConstructible: Sized {
187187
///
188188
/// The expression is minimized by using as many word jets as possible.
189189
fn scribe(ctx: &types::Context, value: &Value) -> Self {
190+
use crate::value::ValueRef;
191+
190192
#[derive(Debug, Clone)]
191-
enum Task {
192-
Process(Value),
193+
enum Task<'v> {
194+
Process(ValueRef<'v>),
193195
MakeLeft,
194196
MakeRight,
195197
MakeProduct,
196198
}
197199

198-
let mut input = vec![Task::Process(value.shallow_clone())];
200+
let mut input = vec![Task::Process(value.as_ref())];
199201
let mut output = vec![];
200202
while let Some(top) = input.pop() {
201203
match top {
@@ -204,13 +206,13 @@ pub trait CoreConstructible: Sized {
204206
output.push(Self::unit(ctx));
205207
} else if let Some(word) = value.to_word() {
206208
output.push(Self::const_word(ctx, word));
207-
} else if let Some(left) = value.to_left() {
209+
} else if let Some(left) = value.as_left() {
208210
input.push(Task::MakeLeft);
209211
input.push(Task::Process(left));
210-
} else if let Some(right) = value.to_right() {
212+
} else if let Some(right) = value.as_right() {
211213
input.push(Task::MakeRight);
212214
input.push(Task::Process(right));
213-
} else if let Some((left, right)) = value.to_product() {
215+
} else if let Some((left, right)) = value.as_product() {
214216
input.push(Task::MakeProduct);
215217
input.push(Task::Process(right));
216218
input.push(Task::Process(left));

src/types/final_data.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ pub struct Final {
3636
bound: CompleteBound,
3737
/// Width of the type, in bits, in the bit machine
3838
bit_width: usize,
39+
/// Whether the type's bit representation has any padding. If this is true,
40+
/// then its "compact" witness-encoded bit-width may be lower than its "padded"
41+
/// bit-machine bit-width.
42+
has_padding: bool,
3943
/// TMR of the type
4044
tmr: Tmr,
4145
}
@@ -83,11 +87,11 @@ impl fmt::Display for Final {
8387
}
8488
continue;
8589
} else {
86-
if data.node.tmr == Tmr::POWERS_OF_TWO[0] {
90+
if data.node.tmr == Tmr::TWO_TWO_N[0] {
8791
f.write_str("2")?;
8892
skipping = Some(data.node.tmr);
8993
}
90-
for (n, tmr) in Tmr::POWERS_OF_TWO.iter().enumerate().skip(1) {
94+
for (n, tmr) in Tmr::TWO_TWO_N.iter().enumerate().skip(1) {
9195
if data.node.tmr == *tmr {
9296
write!(f, "2^{}", 1 << n)?;
9397
skipping = Some(data.node.tmr);
@@ -165,6 +169,7 @@ impl Final {
165169
Arc::new(Final {
166170
bound: CompleteBound::Unit,
167171
bit_width: 0,
172+
has_padding: false,
168173
tmr: Tmr::unit(),
169174
})
170175
}
@@ -192,6 +197,7 @@ impl Final {
192197
Arc::new(Final {
193198
tmr: Tmr::sum(left.tmr, right.tmr),
194199
bit_width: 1 + cmp::max(left.bit_width, right.bit_width),
200+
has_padding: left.has_padding || right.has_padding || left.bit_width != right.bit_width,
195201
bound: CompleteBound::Sum(left, right),
196202
})
197203
}
@@ -201,6 +207,7 @@ impl Final {
201207
Arc::new(Final {
202208
tmr: Tmr::product(left.tmr, right.tmr),
203209
bit_width: left.bit_width + right.bit_width,
210+
has_padding: left.has_padding || right.has_padding,
204211
bound: CompleteBound::Product(left, right),
205212
})
206213
}
@@ -215,6 +222,14 @@ impl Final {
215222
self.bit_width
216223
}
217224

225+
/// Whether the type's bit representation has any padding.
226+
///
227+
/// If this is true, then its "compact" witness-encoded bit-width may be lower
228+
/// than its "padded" bit-machine bit-width.
229+
pub fn has_padding(&self) -> bool {
230+
self.has_padding
231+
}
232+
218233
/// Check if the type is a nested product of units.
219234
/// In this case, values contain no information.
220235
pub fn is_empty(&self) -> bool {
@@ -254,7 +269,7 @@ impl Final {
254269
/// 0 ≤ n < 32.
255270
pub fn as_word(&self) -> Option<u32> {
256271
(0..32u32).find(|&n| {
257-
self.tmr == Tmr::POWERS_OF_TWO[n as usize] // cast safety: 32-bit machine or higher
272+
self.tmr == Tmr::TWO_TWO_N[n as usize] // cast safety: 32-bit machine or higher
258273
})
259274
}
260275

src/types/precomputed.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ use std::convert::TryInto;
2121
use std::sync::Arc;
2222

2323
// Directly use the size of the precomputed TMR table to make sure they're in sync.
24-
const N_POWERS: usize = Tmr::POWERS_OF_TWO.len();
24+
const N_POWERS: usize = Tmr::TWO_TWO_N.len();
2525

2626
thread_local! {
27-
static POWERS_OF_TWO: RefCell<Option<[Arc<Final>; N_POWERS]>> = const { RefCell::new(None) };
27+
static TWO_TWO_N: RefCell<Option<[Arc<Final>; N_POWERS]>> = const { RefCell::new(None) };
2828
}
2929

3030
fn initialize(write: &mut Option<[Arc<Final>; N_POWERS]>) {
@@ -49,9 +49,9 @@ fn initialize(write: &mut Option<[Arc<Final>; N_POWERS]>) {
4949
///
5050
/// # Panics
5151
///
52-
/// Panics if you request a number `n` greater than or equal to [`Tmr::POWERS_OF_TWO`].
52+
/// Panics if you request a number `n` greater than or equal to [`Tmr::TWO_TWO_N`].
5353
pub fn nth_power_of_2(n: usize) -> Arc<Final> {
54-
POWERS_OF_TWO.with(|arr| {
54+
TWO_TWO_N.with(|arr| {
5555
if arr.borrow().is_none() {
5656
initialize(&mut arr.borrow_mut());
5757
}

0 commit comments

Comments
 (0)