Skip to main content

rhdl_ubft/
setup.rs

1//! Starting the signature service: keys in, then go.
2//!
3//! ubft_new derives its key pair at init with an inline Ed25519 call and
4//! reads every replica's public key from `message_ptr` (8 words per
5//! replica). rhdl_ubft hands both to its signature service instead.
6//! [`Setup`] plays the service's host over AXI4-Lite:
7//!
8//! 1. the private key (`sk0..sk3`, 32 bytes) as the signer's seed,
9//! 2. replica `s`'s public key into trusted key slot `s`, for every `s <
10//!    node_num`, read from `message_ptr` with one burst per replica,
11//! 3. the key mask (`node_num` slots), unlimited sign and verify counts,
12//! 4. `ap_start`.
13//!
14//! The service then expands the seed and loads the keys (about 105,000
15//! cycles each for Ed25519) and opens its streams. The protocol can start
16//! at once: its first request waits for the stream to open.
17//!
18//! The register offsets are a [`ServiceMap`], so one sequencer serves the
19//! Ed25519 service and DSig's.
20
21use rhdl::prelude::*;
22
23use crate::fetch::{FetchIn, FetchReq, Fetcher};
24use crate::fetch::idle_fetch_req;
25use crate::ports::{AxiLiteIn, AxiLiteOut, AxiRead, AxiReadResp, idle_lite_in};
26
27/// Where a signature service keeps its session arguments.
28#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
29pub struct ServiceMap {
30    /// `ap_ctrl`.
31    pub ap_ctrl: b12,
32    /// Signatures this session.
33    pub sign_count: b12,
34    /// Verifications this session.
35    pub verify_count: b12,
36    /// Seed word 0 (words at +4).
37    pub seed: b12,
38    /// Trusted key mask.
39    pub key_mask: b12,
40    /// Slot 0's key word 0 (words at +4, slots at +0x20).
41    pub keys: b12,
42}
43
44/// The Ed25519 uBFT service's map (`rhdl_ed25519_scalable_core::ubft`).
45pub const ED25519_MAP: ServiceMap = ServiceMap {
46    ap_ctrl: b12(0x000),
47    sign_count: b12(0x010),
48    verify_count: b12(0x014),
49    seed: b12(0x050),
50    key_mask: b12(0x070),
51    keys: b12(0x400),
52};
53
54/// Inputs of [`Setup`].
55#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
56pub struct SetupIn {
57    /// Begin (one-cycle pulse).
58    pub start: bool,
59    /// The service's register map.
60    pub map: ServiceMap,
61    /// Replicas.
62    pub n: b5,
63    /// The private key.
64    pub sk: [b64; 4],
65    /// `message_ptr`.
66    pub keys_base: b64,
67    /// The service's AXI4-Lite answers.
68    pub svc: AxiLiteOut,
69    /// `message_ptr` reads.
70    pub msg: AxiReadResp,
71}
72
73/// Outputs of [`Setup`].
74#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
75pub struct SetupOut {
76    /// Setting up.
77    pub busy: bool,
78    /// The service was started this cycle.
79    pub done: bool,
80    /// AXI4-Lite requests to the service.
81    pub svc: AxiLiteIn,
82    /// `message_ptr` requests.
83    pub msg: AxiRead,
84}
85
86/// The sequencer's registers.
87#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
88pub struct SetupState {
89    /// 0 idle, 1 seed, 2 fetch a key, 3 wait for it, 4 key words, 5 mask,
90    /// 6 sign count, 7 verify count, 8 start.
91    pub step: b4,
92    /// Word within the step (seed or key words 0..8).
93    pub word: b4,
94    /// Replica whose key is loading.
95    pub slot: b5,
96    /// The key words fetched.
97    pub key: [b32; 8],
98    /// A write is in flight: address and data accepted flags.
99    pub aw_done: bool,
100    /// Data accepted.
101    pub w_done: bool,
102    /// Waiting for the write response.
103    pub b_wait: bool,
104    /// Latched inputs.
105    pub map: ServiceMap,
106    /// Replicas.
107    pub n: b5,
108    /// The private key.
109    pub sk: [b64; 4],
110    /// `message_ptr`.
111    pub keys_base: b64,
112}
113
114/// Service setup sequencer (see the module docs).
115#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
116pub struct Setup {
117    state: rhdl_fpga::core::dff::DFF<SetupState>,
118    fetch: Fetcher,
119}
120
121impl Default for Setup {
122    fn default() -> Self {
123        Self { state: rhdl_fpga::core::dff::DFF::new(SetupState::default()), fetch: Fetcher::default() }
124    }
125}
126
127impl SynchronousIO for Setup {
128    type I = SetupIn;
129    type O = SetupOut;
130    type Kernel = setup_kernel;
131}
132
133/// The sequencer's logic.
134#[kernel]
135pub fn setup_kernel(_cr: ClockReset, i: SetupIn, q: SetupQ) -> (SetupOut, SetupD) {
136    let r = q.state;
137    let mut s = r;
138    let mut o = SetupOut { busy: false, done: false, svc: idle_lite_in(), msg: q.fetch.axi };
139    let mut f = FetchIn { req: idle_fetch_req(), axi: i.msg };
140    f.axi = i.msg;
141    o.msg = q.fetch.axi;
142    o.busy = r.step != b4(0);
143    if r.step == b4(0) && i.start {
144        s.step = b4(1);
145        s.word = b4(0);
146        s.slot = b5(0);
147        s.map = i.map;
148        s.n = i.n;
149        s.sk = i.sk;
150        s.keys_base = i.keys_base;
151    }
152    // The register write of this step, if it has one.
153    let mut write = false;
154    let mut addr = b12(0);
155    let mut data = b32(0);
156    if r.step == b4(1) {
157        write = true;
158        addr = r.map.seed + (r.word.resize::<12>() << b12(2));
159        let mut w = r.sk[0];
160        for k in 0..4 {
161            if (r.word >> b4(1)) == b4(k as u128) {
162                w = r.sk[k];
163            }
164        }
165        data = if (r.word & b4(1)) == b4(1) { (w >> b64(32)).resize() } else { w.resize() };
166    }
167    if r.step == b4(2) {
168        f.req = FetchReq { start: true, base: r.keys_base, word: r.slot.resize::<32>() << b32(3), count: b6(8) };
169        if !q.fetch.busy {
170            s.step = b4(3);
171        }
172    }
173    if r.step == b4(3) && q.fetch.done {
174        for k in 0..8 {
175            s.key[k] = q.fetch.words[k];
176        }
177        s.word = b4(0);
178        s.step = b4(4);
179    }
180    if r.step == b4(4) {
181        write = true;
182        addr = r.map.keys + (r.slot.resize::<12>() << b12(5)) + (r.word.resize::<12>() << b12(2));
183        let mut w = b32(0);
184        for k in 0..8 {
185            if r.word == b4(k as u128) {
186                w = r.key[k];
187            }
188        }
189        data = w;
190    }
191    if r.step == b4(5) {
192        write = true;
193        addr = r.map.key_mask;
194        data = (b32(1) << r.n.resize::<32>()) - b32(1);
195    }
196    if r.step == b4(6) {
197        write = true;
198        addr = r.map.sign_count;
199        data = !b32(0);
200    }
201    if r.step == b4(7) {
202        write = true;
203        addr = r.map.verify_count;
204        data = !b32(0);
205    }
206    if r.step == b4(8) {
207        write = true;
208        addr = r.map.ap_ctrl;
209        data = b32(1);
210    }
211    // One AXI4-Lite write: address and data, then the response.
212    let mut wrote = false;
213    if write && !r.b_wait {
214        o.svc.aw_valid = !r.aw_done;
215        o.svc.aw_addr = addr;
216        o.svc.w_valid = !r.w_done;
217        o.svc.w_data = data;
218        o.svc.w_strb = b4(0xf);
219        let aw = r.aw_done || i.svc.aw_ready;
220        let w = r.w_done || i.svc.w_ready;
221        s.aw_done = aw;
222        s.w_done = w;
223        if aw && w {
224            s.b_wait = true;
225        }
226    }
227    if r.b_wait {
228        o.svc.b_ready = true;
229        if i.svc.b_valid {
230            s.b_wait = false;
231            s.aw_done = false;
232            s.w_done = false;
233            wrote = true;
234        }
235    }
236    if wrote {
237        // Advance to the next write.
238        if r.step == b4(1) {
239            s.word = r.word + b4(1);
240            if r.word == b4(7) {
241                s.step = b4(2);
242            }
243        }
244        if r.step == b4(4) {
245            s.word = r.word + b4(1);
246            if r.word == b4(7) {
247                s.slot = r.slot + b5(1);
248                s.step = if r.slot + b5(1) == r.n { b4(5) } else { b4(2) };
249            }
250        }
251        if r.step == b4(5) {
252            s.step = b4(6);
253        }
254        if r.step == b4(6) {
255            s.step = b4(7);
256        }
257        if r.step == b4(7) {
258            s.step = b4(8);
259        }
260        if r.step == b4(8) {
261            s.step = b4(0);
262            o.done = true;
263        }
264    }
265    (o, SetupD { state: s, fetch: f })
266}