Skip to main content

snarkos_account/
lib.rs

1// Copyright (c) 2019-2026 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
16#![forbid(unsafe_code)]
17
18use snarkvm::{
19    console::{network::prelude::*, types::Field},
20    prelude::*,
21};
22
23use colored::*;
24use core::fmt;
25
26/// A helper struct for an Aleo account.
27#[derive(Clone, Debug)]
28pub struct Account<N: Network> {
29    /// The account private key.
30    private_key: PrivateKey<N>,
31    /// The account view key.
32    view_key: ViewKey<N>,
33    /// The account address.
34    address: Address<N>,
35}
36
37impl<N: Network> Account<N> {
38    /// Samples a new account.
39    pub fn new<R: Rng + CryptoRng>(rng: &mut R) -> Result<Self> {
40        Self::try_from(PrivateKey::new(rng)?)
41    }
42
43    /// Returns the account private key.
44    pub const fn private_key(&self) -> &PrivateKey<N> {
45        &self.private_key
46    }
47
48    /// Returns the account view key.
49    pub const fn view_key(&self) -> &ViewKey<N> {
50        &self.view_key
51    }
52
53    /// Returns the account address.
54    pub const fn address(&self) -> Address<N> {
55        self.address
56    }
57}
58
59impl<N: Network> Account<N> {
60    /// Returns a signature for the given message (as field elements), using the account private key.
61    pub fn sign<R: Rng + CryptoRng>(&self, message: &[Field<N>], rng: &mut R) -> Result<Signature<N>> {
62        Signature::sign(&self.private_key, message, rng)
63    }
64
65    /// Returns a signature for the given message (as bytes), using the account private key.
66    pub fn sign_bytes<R: Rng + CryptoRng>(&self, message: &[u8], rng: &mut R) -> Result<Signature<N>> {
67        Signature::sign_bytes(&self.private_key, message, rng)
68    }
69
70    /// Returns a signature for the given message (as bits), using the account private key.
71    pub fn sign_bits<R: Rng + CryptoRng>(&self, message: &[bool], rng: &mut R) -> Result<Signature<N>> {
72        Signature::sign_bits(&self.private_key, message, rng)
73    }
74
75    /// Verifies a signature for the given message (as fields), using the account address.
76    pub fn verify(&self, message: &[Field<N>], signature: &Signature<N>) -> bool {
77        signature.verify(&self.address, message)
78    }
79
80    /// Verifies a signature for the given message (as bytes), using the account address.
81    pub fn verify_bytes(&self, message: &[u8], signature: &Signature<N>) -> bool {
82        signature.verify_bytes(&self.address, message)
83    }
84
85    /// Verifies a signature for the given message (as bits), using the account address.
86    pub fn verify_bits(&self, message: &[bool], signature: &Signature<N>) -> bool {
87        signature.verify_bits(&self.address, message)
88    }
89}
90
91impl<N: Network> TryFrom<PrivateKey<N>> for Account<N> {
92    type Error = Error;
93
94    /// Initializes a new account from a private key.
95    fn try_from(private_key: PrivateKey<N>) -> Result<Self, Self::Error> {
96        Self::try_from(&private_key)
97    }
98}
99
100impl<N: Network> TryFrom<&PrivateKey<N>> for Account<N> {
101    type Error = Error;
102
103    /// Initializes a new account from a private key.
104    fn try_from(private_key: &PrivateKey<N>) -> Result<Self, Self::Error> {
105        let view_key = ViewKey::try_from(private_key)?;
106        let address = view_key.to_address();
107        Ok(Self { private_key: *private_key, view_key, address })
108    }
109}
110
111impl<N: Network> TryFrom<String> for Account<N> {
112    type Error = Error;
113
114    /// Initializes a new account from a private key string.
115    fn try_from(private_key: String) -> Result<Self, Self::Error> {
116        Self::try_from(&private_key)
117    }
118}
119
120impl<N: Network> TryFrom<&String> for Account<N> {
121    type Error = Error;
122
123    /// Initializes a new account from a private key string.
124    fn try_from(private_key: &String) -> Result<Self, Self::Error> {
125        Self::from_str(private_key.as_str())
126    }
127}
128
129impl<N: Network> TryFrom<&str> for Account<N> {
130    type Error = Error;
131
132    /// Initializes a new account from a private key string.
133    fn try_from(private_key: &str) -> Result<Self, Self::Error> {
134        Self::from_str(private_key)
135    }
136}
137
138impl<N: Network> FromStr for Account<N> {
139    type Err = Error;
140
141    /// Initializes a new account from a private key string.
142    fn from_str(private_key: &str) -> Result<Self, Self::Err> {
143        Self::try_from(PrivateKey::from_str(private_key)?)
144    }
145}
146
147impl<N: Network> Display for Account<N> {
148    /// Renders the account as a string.
149    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
150        write!(
151            f,
152            " {:>12}  {}\n {:>12}  {}\n {:>12}  {}",
153            "Private Key".cyan().bold(),
154            self.private_key,
155            "View Key".cyan().bold(),
156            self.view_key,
157            "Address".cyan().bold(),
158            self.address
159        )
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use snarkvm::prelude::MainnetV0;
167
168    type CurrentNetwork = MainnetV0;
169
170    #[test]
171    fn test_sign() {
172        // Initialize the RNG.
173        let mut rng = TestRng::default();
174        // Prepare the account and message.
175        let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
176        let message = vec![Field::rand(&mut rng); 10];
177        // Sign and verify.
178        let signature = account.sign(&message, &mut rng).unwrap();
179        assert!(account.verify(&message, &signature));
180    }
181
182    #[test]
183    fn test_sign_bytes() {
184        // Initialize the RNG.
185        let mut rng = TestRng::default();
186        // Prepare the account and message.
187        let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
188
189        // TODO(kaimast): remove once we upgrade the rand crate
190        let message = (0..10).map(|_| rng.r#gen::<u8>()).collect::<Vec<u8>>();
191        // Sign and verify.
192        let signature = account.sign_bytes(&message, &mut rng).unwrap();
193        assert!(account.verify_bytes(&message, &signature));
194    }
195
196    #[test]
197    fn test_sign_bits() {
198        // Initialize the RNG.
199        let mut rng = TestRng::default();
200        // Prepare the account and message.
201        let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
202        let message = (0..10).map(|_| rng.r#gen::<bool>()).collect::<Vec<bool>>();
203        // Sign and verify.
204        let signature = account.sign_bits(&message, &mut rng).unwrap();
205        assert!(account.verify_bits(&message, &signature));
206    }
207}