Skip to content

Commit feb5671

Browse files
committed
Merge #328: Improve Display for Value in several ways
5e5fbe2 bit_machine: add missing space to StderrTracker (Andrew Poelstra) 271dde9 value: display left and rights as L(x) and R(x); drop DispUnlessUnit (Andrew Poelstra) 6c88a8c value: write out bitstrings with len > 4 as hex rather than binary (Andrew Poelstra) d2da3a0 value: write out power-of-two length bitstrings compactly in Display (Andrew Poelstra) 1ca2498 value: move iterator methods from Value to ValueRef (Andrew Poelstra) 38c5776 value: impl Copy for ValueRef (Andrew Poelstra) 22d5618 value: use ValueRef internally in RawByteIter (Andrew Poelstra) Pull request description: Now we: * display bits and pairs of bits as bitstrings prefixed with `0b` * display any bitstrings of length 4, 8, 16, ..., 2^32 as a hex string prefixed with `0x` * display any remaining sum types as `L(...)` or `R(...)` rather than `0...` or `1...` As an example of the improvement, consider this sample output from `StderrTracker`. Previously we had ``` [ 58] exec jet(sha_256_ctx_8_finalize) (2^256? × (2^128? × (2^64? × (2^32? × (2^16? × 2^8?))))) × (2^64 × 2^256) → 2^256 input ((1((((((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))),(((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))))),((((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))),(((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))))),(((((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))),(((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))))),((((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))),(((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))))))),(0,(0,(0,(0,0))))),(((((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0))))),(((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))),((((0,0),(0,0)),((0,0),(0,0))),(((0,0),(0,0)),((0,0),(0,0)))))),((((((((0,1),(1,0)),((1,0),(1,0))),(((0,0),(0,0)),((1,0),(0,1)))),((((1,1),(1,0)),((0,1),(1,0))),(((0,1),(1,0)),((0,1),(1,1))))),(((((1,0),(1,1)),((1,0),(1,1))),(((0,1),(1,0)),((0,1),(1,1)))),((((1,0),(1,0)),((1,1),(1,0))),(((1,0),(0,0)),((0,1),(0,1)))))),((((((0,0),(1,1)),((1,1),(0,0))),(((0,1),(1,0)),((1,1),(1,0)))),((((1,1),(1,1)),((0,0),(1,1))),(((0,1),(1,1)),((0,0),(1,0))))),(((((1,0),(1,0)),((0,1),(0,1))),(((0,1),(0,0)),((1,1),(1,1)))),((((1,1),(1,1)),((0,1),(0,1))),(((0,0),(1,1)),((1,0),(1,0))))))),(((((((0,1),(0,1)),((0,0),(0,1))),(((0,0),(0,0)),((1,1),(1,0)))),((((0,1),(0,1)),((0,0),(1,0))),(((0,1),(1,1)),((1,1),(1,1))))),(((((1,0),(0,1)),((1,0),(1,1))),(((0,0),(0,0)),((0,1),(0,1)))),((((0,1),(1,0)),((1,0),(0,0))),(((1,0),(0,0)),((1,1),(0,0)))))),((((((0,0),(0,1)),((1,1),(1,1))),(((1,0),(0,0)),((0,0),(1,1)))),((((1,1),(0,1)),((1,0),(0,1))),(((1,0),(1,0)),((1,0),(1,1))))),(((((0,1),(0,1)),((1,0),(1,1))),(((1,1),(1,0)),((0,0),(0,0)))),((((1,1),(0,0)),((1,1),(0,1))),(((0,0),(0,1)),((1,0),(0,1)))))))))) output ((((((((0,1),(1,0)),((0,1),(1,0))),(((0,1),(1,0)),((1,0),(0,0)))),((((0,1),(1,1)),((1,0),(1,0))),(((1,0),(1,0)),((1,1),(0,1))))),(((((1,1),(1,1)),((1,0),(0,0))),(((0,1),(1,0)),((0,0),(1,0)))),((((1,0),(1,1)),((1,1),(0,1))),(((0,1),(1,1)),((0,1),(1,1)))))),((((((0,1),(1,0)),((1,1),(0,0))),(((1,0),(0,0)),((1,1),(1,1)))),((((1,1),(0,0)),((0,0),(0,1))),(((1,0),(0,0)),((1,0),(1,1))))),(((((1,0),(0,0)),((1,1),(1,0))),(((1,0),(0,1)),((1,1),(1,1)))),((((1,0),(0,0)),((1,1),(1,0))),(((0,0),(1,0)),((0,0),(0,0))))))),(((((((0,0),(0,0)),((1,0),(0,0))),(((1,0),(0,1)),((0,1),(1,1)))),((((0,0),(0,1)),((0,1),(0,0))),(((1,0),(0,0)),((0,1),(0,1))))),(((((0,1),(1,0)),((1,1),(1,0))),(((1,1),(1,0)),((0,0),(1,0)))),((((0,0),(1,1)),((0,0),(1,1))),(((1,0),(1,1)),((0,0),(1,1)))))),((((((1,0),(0,1)),((0,0),(0,0))),(((0,0),(1,0)),((1,0),(1,0)))),((((0,1),(0,1)),((1,0),(0,1))),(((0,0),(0,1)),((1,1),(0,1))))),(((((0,0),(0,0)),((1,1),(0,1))),(((0,1),(0,1)),((1,1),(1,1)))),((((0,0),(1,0)),((1,0),(0,1))),(((0,0),(1,0)),((0,1),(0,1)))))))) ``` Now we have ``` [ 58] exec jet(sha_256_ctx_8_finalize) (2^256? × (2^128? × (2^64? × (2^32? × (2^16? × 2^8?))))) × (2^64 × 2^256) → 2^256 input ((R(0x0202020202020202020202020202020202020202020202020202020202020202),(L(ε),(L(ε),(L(ε),(L(ε),L(ε)))))),(0x0000000000000000,0x6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19)) output 0x75877bb41d393b5fb8455ce60ecd8dda001d06316496b14dfa7f895656eeca4a ``` I would like to get this in before #327. ACKs for top commit: KyrylR: ACK 5e5fbe2 Tree-SHA512: 4cd37448ac9e62153255d3426ac827d6f654d2df883bdbb386856095549fb1c5cb053963f49c25b78ae6a12c135401f8cc30a5dde036bdd37c6c0ec47f8a65f1
2 parents 7c3cbb3 + 5e5fbe2 commit feb5671

2 files changed

Lines changed: 88 additions & 38 deletions

File tree

src/bit_machine/tracker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl<J: Jet> ExecTracker<J> for StderrTracker {
163163
NodeOutput::Success(mut output) => {
164164
let output_val = Value::from_padded_bits(&mut output, &node.arrow().target)
165165
.expect("output from bit machine will always be well-formed");
166-
eprintln!(" output {output_val}");
166+
eprintln!(" output {output_val}");
167167
}
168168
}
169169

src/value.rs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
use crate::dag::{Dag, DagLike};
99
use crate::types::{CompleteBound, Final};
10-
use crate::BitIter;
10+
use crate::{BitIter, Tmr};
1111

1212
use crate::{BitCollector, EarlyEndOfStreamError};
1313
use core::{cmp, fmt, iter};
@@ -38,7 +38,7 @@ pub struct Value {
3838
}
3939

4040
/// Reference to a value, or to a sub-value of a value.
41-
#[derive(Debug, Clone)]
41+
#[derive(Debug, Clone, Copy)]
4242
pub struct ValueRef<'v> {
4343
inner: &'v Arc<[u8]>,
4444
bit_offset: usize,
@@ -101,7 +101,7 @@ impl DagLike for ValueRef<'_> {
101101
}
102102
}
103103

104-
impl ValueRef<'_> {
104+
impl<'v> ValueRef<'v> {
105105
/// Check if the value is a unit.
106106
pub fn is_unit(&self) -> bool {
107107
self.ty.is_unit()
@@ -196,10 +196,38 @@ impl ValueRef<'_> {
196196
n,
197197
})
198198
}
199+
200+
/// Yields an iterator over the "raw bytes" of the value.
201+
///
202+
/// The returned bytes match the padded bit-encoding of the value. You
203+
/// may wish to call [`Self::iter_padded`] instead to obtain the bits,
204+
/// but this method is more efficient in some contexts.
205+
pub fn raw_byte_iter(&self) -> RawByteIter<'v> {
206+
RawByteIter {
207+
value: *self,
208+
yielded_bytes: 0,
209+
}
210+
}
211+
212+
/// Return an iterator over the compact bit encoding of the value.
213+
///
214+
/// This encoding is used for writing witness data and for computing IHRs.
215+
pub fn iter_compact(&self) -> CompactBitsIter<'v> {
216+
CompactBitsIter::new(*self)
217+
}
218+
219+
/// Return an iterator over the padded bit encoding of the value.
220+
///
221+
/// This encoding is used to represent the value in the Bit Machine.
222+
pub fn iter_padded(&self) -> PreOrderIter<'v> {
223+
PreOrderIter {
224+
inner: BitIter::new(self.raw_byte_iter()).take(self.ty.bit_width()),
225+
}
226+
}
199227
}
200228

201229
pub struct RawByteIter<'v> {
202-
value: &'v Value,
230+
value: ValueRef<'v>,
203231
yielded_bytes: usize,
204232
}
205233

@@ -591,26 +619,21 @@ impl Value {
591619
/// may wish to call [`Self::iter_padded`] instead to obtain the bits,
592620
/// but this method is more efficient in some contexts.
593621
pub fn raw_byte_iter(&self) -> RawByteIter<'_> {
594-
RawByteIter {
595-
value: self,
596-
yielded_bytes: 0,
597-
}
622+
self.as_ref().raw_byte_iter()
598623
}
599624

600625
/// Return an iterator over the compact bit encoding of the value.
601626
///
602627
/// This encoding is used for writing witness data and for computing IHRs.
603628
pub fn iter_compact(&self) -> CompactBitsIter<'_> {
604-
CompactBitsIter::new(self.as_ref())
629+
self.as_ref().iter_compact()
605630
}
606631

607632
/// Return an iterator over the padded bit encoding of the value.
608633
///
609634
/// This encoding is used to represent the value in the Bit Machine.
610635
pub fn iter_padded(&self) -> PreOrderIter<'_> {
611-
PreOrderIter {
612-
inner: BitIter::new(self.raw_byte_iter()).take(self.ty.bit_width()),
613-
}
636+
self.as_ref().iter_padded()
614637
}
615638

616639
/// Check if the value is of the given type.
@@ -736,43 +759,70 @@ impl fmt::Display for Value {
736759
// that we handle products more explicitly.
737760
enum S<'v> {
738761
Disp(ValueRef<'v>),
739-
DispUnlessUnit(ValueRef<'v>),
740762
DispCh(char),
741763
}
742764

743765
let mut stack = Vec::with_capacity(1024);
744-
// Next node to visit, and a boolean indicating whether we should
745-
// display units explicitly (turned off for sums, since a sum of
746-
// a unit is displayed simply as 0 or 1.
766+
// Next node to visit.
747767
stack.push(S::Disp(self.as_ref()));
748768

749-
while let Some(next) = stack.pop() {
769+
'main_loop: while let Some(next) = stack.pop() {
750770
let value = match next {
751-
S::Disp(ref value) | S::DispUnlessUnit(ref value) => value,
771+
S::Disp(ref value) => value,
752772
S::DispCh(ch) => {
753773
write!(f, "{}", ch)?;
754774
continue;
755775
}
756776
};
757777

758778
if value.is_unit() {
759-
if !matches!(next, S::DispUnlessUnit(..)) {
760-
f.write_str("ε")?;
761-
}
762-
} else if let Some(l_value) = value.as_left() {
763-
f.write_str("0")?;
764-
stack.push(S::DispUnlessUnit(l_value));
765-
} else if let Some(r_value) = value.as_right() {
766-
f.write_str("1")?;
767-
stack.push(S::DispUnlessUnit(r_value));
768-
} else if let Some((l_value, r_value)) = value.as_product() {
769-
stack.push(S::DispCh(')'));
770-
stack.push(S::Disp(r_value));
771-
stack.push(S::DispCh(','));
772-
stack.push(S::Disp(l_value));
773-
stack.push(S::DispCh('('));
779+
f.write_str("ε")?;
774780
} else {
775-
unreachable!()
781+
// First, write any bitstrings out
782+
for tmr in &Tmr::TWO_TWO_N {
783+
if value.ty.tmr() == *tmr {
784+
if value.ty.bit_width() < 4 {
785+
f.write_str("0b")?;
786+
for bit in value.iter_padded() {
787+
f.write_str(if bit { "1" } else { "0" })?;
788+
}
789+
} else {
790+
f.write_str("0x")?;
791+
// Annoyingly `array_chunks` is unstable so we have to do it manually
792+
// https://github.com/rust-lang/rust/issues/100450
793+
let mut iter = value.iter_padded();
794+
while let (Some(a), Some(b), Some(c), Some(d)) =
795+
(iter.next(), iter.next(), iter.next(), iter.next())
796+
{
797+
let n = (u8::from(a) << 3)
798+
+ (u8::from(b) << 2)
799+
+ (u8::from(c) << 1)
800+
+ u8::from(d);
801+
write!(f, "{:x}", n)?;
802+
}
803+
}
804+
continue 'main_loop;
805+
}
806+
}
807+
808+
// If we don't have a bitstring, then write out the explicit value.
809+
if let Some(l_value) = value.as_left() {
810+
f.write_str("L(")?;
811+
stack.push(S::DispCh(')'));
812+
stack.push(S::Disp(l_value));
813+
} else if let Some(r_value) = value.as_right() {
814+
f.write_str("R(")?;
815+
stack.push(S::DispCh(')'));
816+
stack.push(S::Disp(r_value));
817+
} else if let Some((l_value, r_value)) = value.as_product() {
818+
stack.push(S::DispCh(')'));
819+
stack.push(S::Disp(r_value));
820+
stack.push(S::DispCh(','));
821+
stack.push(S::Disp(l_value));
822+
stack.push(S::DispCh('('));
823+
} else {
824+
unreachable!()
825+
}
776826
}
777827
}
778828
Ok(())
@@ -1070,9 +1120,9 @@ mod tests {
10701120
fn value_display() {
10711121
// Only test a couple values becasue we probably want to change this
10721122
// at some point and will have to redo this test.
1073-
assert_eq!(Value::u1(0).to_string(), "0",);
1074-
assert_eq!(Value::u1(1).to_string(), "1",);
1075-
assert_eq!(Value::u4(6).to_string(), "((0,1),(1,0))",);
1123+
assert_eq!(Value::u1(0).to_string(), "0b0",);
1124+
assert_eq!(Value::u1(1).to_string(), "0b1",);
1125+
assert_eq!(Value::u4(6).to_string(), "0x6",);
10761126
}
10771127

10781128
#[test]

0 commit comments

Comments
 (0)