-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinscribe.rs
More file actions
133 lines (131 loc) · 3.52 KB
/
inscribe.rs
File metadata and controls
133 lines (131 loc) · 3.52 KB
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
use crate::decree::FSInput;
use crate::error::DecreeResult;
pub const INSCRIBE_LENGTH: usize = 64;
pub type InscribeBuffer = [u8; INSCRIBE_LENGTH];
/// The `Inscribe` trait is a derivable trait for structs that makes it easy to incorporate
/// contextual data into Fiat-Shamir transcripts. There are two main methods that the trait
/// requires:
///
/// `const MARK: &'static str`
///
/// and
///
/// `fn get_inscription(&self) -> FSInput`
///
/// For derived structs, the `get_inscription` method will do the following:
/// - Initialize a TupleHash with the contents of `MARK`
/// - For each member of the struct, do one of three things:
/// + For `Inscribe` implementers, call `get_inscription` and add the results to the
/// TupleHash
/// + Use the `bcs` library to serialize the member and add the results to the TupleHash
/// + Skip the item entirely
/// - At the end, the TupleHash result is returned
///
/// By default, struct members are assumed to implement the `Inscribe` trait, but this can be
/// overridden using `inscribe` attributes:
///
/// Examples:
///
/// This following code should fail to compile, as the default behavior is to call
/// `get_inscription` on `x` and `y`, even though the `i32` type doesn't implement the `Inscribe`
/// trait.
///
/// ```compile_fail
/// # use decree::Inscribe;
/// # use decree::inscribe::InscribeBuffer;
/// #[derive(Inscribe)]
/// pub struct Point {
/// x: i32,
/// y: i32,
/// }
/// ```
///
/// On the other hand, if we annotate both `x` and `y` with `inscribe(serialize)`, the code will
/// compile just fine, with both values being serialized using the `bcs` library.
///
/// ```
/// # use decree::Inscribe;
/// # use decree::inscribe::InscribeBuffer;
/// #[derive(Inscribe)]
/// pub struct Point {
/// #[inscribe(serialize)]
/// x: i32,
/// #[inscribe(serialize)]
/// y: i32,
/// }
/// ```
///
/// Note that we can't specify two different handlings for the same struct member:
///
/// ```compile_fail
/// # use decree::Inscribe;
/// # use decree::inscribe::InscribeBuffer;
/// #[derive(Inscribe)]
/// pub struct Point {
/// #[inscribe(serialize)]
/// #[inscribe(skip)]
/// x: i32,
/// y: i32,
/// }
/// ```
///
/// # Tests
///
/// ```
/// # use decree::Inscribe;
/// # use decree::inscribe::InscribeBuffer;
/// #[derive(Inscribe)]
/// pub struct Point {
/// #[inscribe(serialize)]
/// x: i32,
/// #[inscribe(serialize)]
/// y: i32,
/// }
///
/// #[derive(Inscribe)]
/// pub struct Proof {
/// basis: Point,
/// result: Point,
/// #[inscribe(serialize)]
/// challenge: Vec<u8>,
/// }
/// ```
///
/// ```
/// # use decree::Inscribe;
/// # use decree::inscribe::InscribeBuffer;
/// # use decree::decree::FSInput;
/// # use decree::error::Error;
/// # use decree::error::DecreeResult;
/// #[derive(Inscribe)]
/// pub struct Point {
/// #[inscribe(serialize)]
/// x: i32,
/// #[inscribe(serialize)]
/// y: i32,
/// }
///
/// #[derive(Inscribe)]
/// #[inscribe_addl(addl_context)]
/// pub struct Proof {
/// basis: Point,
/// result: Point,
/// #[inscribe(serialize)]
/// challenge: Vec<u8>,
/// }
/// impl Proof {
/// fn addl_context(&self) -> Result<Vec<u8>, Error> {
/// let j = "xyproof".as_bytes();
/// Ok(j.to_vec())
/// }
/// }
/// ```
///
pub trait Inscribe {
const MARK: &'static str;
fn get_inscription(&self) -> DecreeResult<FSInput>;
fn get_additional(&self) -> DecreeResult<FSInput> {
let x: Vec<u8> = Vec::new();
Ok(x)
}
}