snarkos_node_router_messages/
challenge_response.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18use snarkvm::{
19    ledger::narwhal::Data,
20    prelude::{Field, FromBytes, ToBytes},
21};
22
23use std::borrow::Cow;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct ChallengeResponse<N: Network> {
27    pub genesis_header: Header<N>,
28    pub restrictions_id: Field<N>,
29    pub signature: Data<Signature<N>>,
30    pub nonce: u64,
31}
32
33impl<N: Network> MessageTrait for ChallengeResponse<N> {
34    /// Returns the message name.
35    #[inline]
36    fn name(&self) -> Cow<'static, str> {
37        "ChallengeResponse".into()
38    }
39}
40
41impl<N: Network> ToBytes for ChallengeResponse<N> {
42    fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
43        self.genesis_header.write_le(&mut writer)?;
44        self.restrictions_id.write_le(&mut writer)?;
45        self.signature.write_le(&mut writer)?;
46        self.nonce.write_le(&mut writer)
47    }
48}
49
50impl<N: Network> FromBytes for ChallengeResponse<N> {
51    fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
52        Ok(Self {
53            genesis_header: Header::read_le(&mut reader)?,
54            restrictions_id: Field::read_le(&mut reader)?,
55            signature: Data::read_le(&mut reader)?,
56            nonce: u64::read_le(reader)?,
57        })
58    }
59}
60
61#[cfg(test)]
62pub mod prop_tests {
63    use crate::ChallengeResponse;
64    use snarkvm::{
65        console::prelude::{FromBytes, ToBytes},
66        ledger::{narwhal::Data, snarkvm_ledger_test_helpers::sample_genesis_block},
67        prelude::{Field, PrivateKey, Signature, block::Header},
68        utilities::rand::{TestRng, Uniform},
69    };
70
71    use bytes::{Buf, BufMut, BytesMut};
72    use proptest::prelude::{BoxedStrategy, Strategy, any};
73    use test_strategy::proptest;
74
75    type CurrentNetwork = snarkvm::prelude::MainnetV0;
76
77    pub fn any_restrictions_id() -> Field<CurrentNetwork> {
78        Uniform::rand(&mut TestRng::default())
79    }
80
81    pub fn any_signature() -> BoxedStrategy<Signature<CurrentNetwork>> {
82        (0..64)
83            .prop_map(|message_size| {
84                let rng = &mut TestRng::default();
85                let message: Vec<_> = (0..message_size).map(|_| Uniform::rand(rng)).collect();
86                let private_key = PrivateKey::new(rng).unwrap();
87                Signature::sign(&private_key, &message, rng).unwrap()
88            })
89            .boxed()
90    }
91
92    pub fn any_genesis_header() -> BoxedStrategy<Header<CurrentNetwork>> {
93        any::<u64>().prop_map(|seed| *sample_genesis_block(&mut TestRng::fixed(seed)).header()).boxed()
94    }
95
96    pub fn any_challenge_response() -> BoxedStrategy<ChallengeResponse<CurrentNetwork>> {
97        (any_genesis_header(), any_signature(), any::<u64>())
98            .prop_map(|(genesis_header, sig, nonce)| ChallengeResponse {
99                genesis_header,
100                restrictions_id: any_restrictions_id(),
101                signature: Data::Object(sig),
102                nonce,
103            })
104            .boxed()
105    }
106
107    #[proptest]
108    fn challenge_response_roundtrip(#[strategy(any_challenge_response())] original: ChallengeResponse<CurrentNetwork>) {
109        let mut buf = BytesMut::default().writer();
110        ChallengeResponse::write_le(&original, &mut buf).unwrap();
111
112        let deserialized: ChallengeResponse<CurrentNetwork> =
113            ChallengeResponse::read_le(buf.into_inner().reader()).unwrap();
114
115        assert_eq!(original.genesis_header, deserialized.genesis_header);
116        assert_eq!(
117            original.signature.deserialize_blocking().unwrap(),
118            deserialized.signature.deserialize_blocking().unwrap()
119        );
120    }
121}