mod.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm 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  mod equal;
 17  mod from;
 18  mod from_private_key;
 19  mod helpers;
 20  mod ternary;
 21  mod to_address;
 22  
 23  #[cfg(test)]
 24  use alphavm_circuit_types::environment::{assert_count, assert_output_mode, assert_scope};
 25  
 26  use crate::PrivateKey;
 27  use alphavm_circuit_network::Alpha;
 28  use alphavm_circuit_types::{Address, Boolean, Field, Group, Scalar, environment::prelude::*};
 29  
 30  #[derive(Clone)]
 31  pub struct ComputeKey<A: Alpha> {
 32      /// The signature public key `pk_sig` := G^sk_sig.
 33      pk_sig: Group<A>,
 34      /// The signature public randomizer `pr_sig` := G^r_sig.
 35      pr_sig: Group<A>,
 36      /// The PRF secret key `sk_prf` := RO(G^sk_sig || G^r_sig).
 37      sk_prf: Scalar<A>,
 38  }
 39  
 40  impl<A: Alpha> Inject for ComputeKey<A> {
 41      type Primitive = console::ComputeKey<A::Network>;
 42  
 43      /// Initializes an account compute key from the given mode and native compute key.
 44      fn new(mode: Mode, compute_key: Self::Primitive) -> Self {
 45          // Inject `pk_sig`.
 46          let pk_sig = Group::new(mode, compute_key.pk_sig());
 47          // Inject `pr_sig`.
 48          let pr_sig = Group::new(mode, compute_key.pr_sig());
 49          // Output the compute key.
 50          Self::from((pk_sig, pr_sig))
 51      }
 52  }
 53  
 54  impl<A: Alpha> ComputeKey<A> {
 55      /// Returns the signature public key.
 56      pub const fn pk_sig(&self) -> &Group<A> {
 57          &self.pk_sig
 58      }
 59  
 60      /// Returns the signature public randomizer.
 61      pub const fn pr_sig(&self) -> &Group<A> {
 62          &self.pr_sig
 63      }
 64  
 65      /// Returns the PRF secret key.
 66      pub const fn sk_prf(&self) -> &Scalar<A> {
 67          &self.sk_prf
 68      }
 69  }
 70  
 71  impl<A: Alpha> Eject for ComputeKey<A> {
 72      type Primitive = console::ComputeKey<A::Network>;
 73  
 74      /// Ejects the mode of the compute key.
 75      fn eject_mode(&self) -> Mode {
 76          (&self.pk_sig, &self.pr_sig, &self.sk_prf).eject_mode()
 77      }
 78  
 79      /// Ejects the compute key.
 80      fn eject_value(&self) -> Self::Primitive {
 81          match Self::Primitive::try_from((&self.pk_sig, &self.pr_sig).eject_value()) {
 82              Ok(compute_key) => compute_key,
 83              Err(error) => A::halt(format!("Failed to eject the compute key: {error}")),
 84          }
 85      }
 86  }
 87  
 88  #[cfg(test)]
 89  pub(crate) mod tests {
 90      use super::*;
 91      use crate::{Circuit, helpers::generate_account};
 92  
 93      use anyhow::Result;
 94  
 95      const ITERATIONS: u64 = 250;
 96  
 97      fn check_new(
 98          mode: Mode,
 99          num_constants: u64,
100          num_public: u64,
101          num_private: u64,
102          num_constraints: u64,
103      ) -> Result<()> {
104          for i in 0..ITERATIONS {
105              // Generate a private key, compute key, view key, and address.
106              let (_private_key, compute_key, _view_key, _address) = generate_account()?;
107  
108              Circuit::scope(format!("New {mode}"), || {
109                  let candidate = ComputeKey::<Circuit>::new(mode, compute_key);
110                  match mode.is_constant() {
111                      true => assert_eq!(Mode::Constant, candidate.eject_mode()),
112                      false => assert_eq!(Mode::Private, candidate.eject_mode()),
113                  };
114                  assert_eq!(compute_key, candidate.eject_value());
115                  // TODO (howardwu): Resolve skipping the cost count checks for the burn-in round.
116                  if i > 0 {
117                      assert_scope!(num_constants, num_public, num_private, num_constraints);
118                  }
119              });
120              Circuit::reset();
121          }
122          Ok(())
123      }
124  
125      #[test]
126      fn test_compute_key_new_constant() -> Result<()> {
127          check_new(Mode::Constant, 274, 0, 0, 0)
128      }
129  
130      #[test]
131      fn test_compute_key_new_public() -> Result<()> {
132          check_new(Mode::Public, 9, 4, 869, 873)
133      }
134  
135      #[test]
136      fn test_compute_key_new_private() -> Result<()> {
137          check_new(Mode::Private, 9, 0, 873, 873)
138      }
139  }