Skip to main content

airbender_crypto/secp256k1/
context.rs

1#[cfg(feature = "alloc")]
2use alloc::boxed::Box;
3#[cfg(feature = "alloc")]
4use core::alloc::{AllocError, Allocator, Layout};
5
6use super::points::{AffineStorage, JacobianConst};
7
8pub(crate) const WINDOW_A: usize = 5;
9
10pub(crate) const WINDOW_G: usize = 10;
11
12pub(crate) const ECMULT_TABLE_SIZE_A: usize = 1 << (WINDOW_A - 2);
13pub(crate) const ECMULT_TABLE_SIZE_G: usize = 1 << (WINDOW_G - 2);
14pub(crate) const WNAF_BITS: usize = 129;
15
16pub struct ECMultContext {
17    pub(crate) pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G],
18    pub(crate) pre_g_128: [AffineStorage; ECMULT_TABLE_SIZE_G],
19}
20
21#[cfg(feature = "secp256k1-static-context")]
22pub(crate) const ECRECOVER_CONTEXT: ECMultContext = ECMultContext::const_new();
23
24impl ECMultContext {
25    /// Creates a new context instance on the stack.
26    /// Calling this function in runtime is likely to cause stack overflow.
27    /// Instead, use `new_in` to create an instance on the heap
28    pub const fn const_new() -> Self {
29        let mut context = Self {
30            pre_g: [AffineStorage::DEFAULT; ECMULT_TABLE_SIZE_G],
31            pre_g_128: [AffineStorage::DEFAULT; ECMULT_TABLE_SIZE_G],
32        };
33
34        context.initialize();
35
36        context
37    }
38
39    const fn compute_table(table: &mut [AffineStorage; ECMULT_TABLE_SIZE_G], gen: &JacobianConst) {
40        use const_for::const_for;
41
42        let mut gj = *gen;
43        // 1 * G
44        table[0] = gj.to_affine_storage_const();
45
46        let g_doubled = gen.double(None);
47        // step by 2*G
48        let g_doubled = g_doubled.to_affine_const();
49
50        const_for!(i in 1..ECMULT_TABLE_SIZE_G => {
51            // += 2 * G
52            gj = gj.add_ge(&g_doubled, None);
53            // write it down
54            table[i] = gj.to_affine_storage_const();
55        });
56    }
57
58    const fn initialize(&mut self) {
59        let mut gj = JacobianConst::GENERATOR;
60
61        Self::compute_table(&mut self.pre_g, &gj);
62
63        use const_for::const_for;
64        const_for!(_ in 0..128 => {
65            gj = gj.double(None);
66        });
67
68        Self::compute_table(&mut self.pre_g_128, &gj);
69    }
70
71    #[cfg(feature = "alloc")]
72    pub fn new_in<A: Allocator>(allocator: A) -> Result<Box<Self, A>, AllocError> {
73        let mut context = unsafe {
74            let layout = Layout::new::<ECMultContext>();
75            let ptr = allocator.allocate(layout)?.cast::<ECMultContext>().as_ptr();
76            let mut this = Box::from_raw_in(ptr, allocator);
77
78            for i in 0..ECMULT_TABLE_SIZE_G {
79                this.pre_g[i] = AffineStorage::DEFAULT;
80                this.pre_g_128[i] = AffineStorage::DEFAULT;
81            }
82
83            this
84        };
85
86        context.initialize();
87
88        Ok(context)
89    }
90
91    pub fn new_from_raw_unchecked(
92        pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G],
93        pre_g_128: [AffineStorage; ECMULT_TABLE_SIZE_G],
94    ) -> Self {
95        Self { pre_g, pre_g_128 }
96    }
97}