taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

signature.rs (3248B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use aws_lc_rs::{
     18     digest::{Context, SHA512},
     19     signature::{ED25519, Ed25519KeyPair, UnparsedPublicKey},
     20 };
     21 
     22 use crate::{
     23     api::{EddsaPublicKey, EddsaSignature},
     24     types::{amount::Amount, payto::PaytoURI, timestamp::TalerTimestamp},
     25 };
     26 
     27 pub trait Signature<const N: usize> {
     28     const PURPOSE: u32;
     29 
     30     fn signature_bytes(&self, buf: Buf<N>) -> Buf<N>;
     31 
     32     fn sign(&self, pair: &Ed25519KeyPair) -> EddsaSignature {
     33         let msg = self
     34             .signature_bytes(Buf::new().put_u32(N as u32).put_u32(Self::PURPOSE))
     35             .finish();
     36         let signature = pair.sign(&msg);
     37         EddsaSignature::try_from(signature.as_ref()).unwrap()
     38     }
     39 
     40     fn verify(&self, key: &EddsaPublicKey, sig: &EddsaSignature) -> bool {
     41         let msg = self
     42             .signature_bytes(Buf::new().put_u32(N as u32).put_u32(Self::PURPOSE))
     43             .finish();
     44         UnparsedPublicKey::new(&ED25519, key.as_ref())
     45             .verify(&msg, sig.as_ref())
     46             .is_ok()
     47     }
     48 }
     49 
     50 /** Buffer for signature bytes  */
     51 pub struct Buf<const N: usize> {
     52     buf: [u8; N],
     53     pos: usize,
     54 }
     55 
     56 impl<const N: usize> Buf<N> {
     57     pub fn new() -> Self {
     58         Self {
     59             buf: [0; N],
     60             pos: 0,
     61         }
     62     }
     63 
     64     pub fn put_u16(self, nb: u16) -> Self {
     65         // Numbers are network order encoded
     66         self.put(&nb.to_be_bytes())
     67     }
     68 
     69     pub fn put_u32(self, nb: u32) -> Self {
     70         // Numbers are network order encoded
     71         self.put(&nb.to_be_bytes())
     72     }
     73 
     74     pub fn put_u64(self, nb: u64) -> Self {
     75         // Numbers are network order encoded
     76         self.put(&nb.to_be_bytes())
     77     }
     78 
     79     pub fn put_amount(self, amount: Amount) -> Self {
     80         self.put(&amount.signature_bytes())
     81     }
     82 
     83     pub fn put_timestamp(self, timestamp: TalerTimestamp) -> Self {
     84         self.put(&timestamp.signature_bytes())
     85     }
     86 
     87     pub fn put_payto(self, payto: &PaytoURI) -> Self {
     88         // Payto are encoded into a c string, hashed using sha-512 and then truncated to 32 bytes
     89         let mut ctx = Context::new(&SHA512);
     90         ctx.update(payto.as_ref().as_str().as_bytes());
     91         ctx.update(&[0]);
     92         self.put(&ctx.finish().as_ref()[..32])
     93     }
     94 
     95     pub fn put(mut self, bytes: &[u8]) -> Self {
     96         let end = self.pos + bytes.len();
     97         self.buf[self.pos..end].copy_from_slice(bytes);
     98         self.pos = end;
     99         self
    100     }
    101 
    102     pub fn finish(self) -> [u8; N] {
    103         self.buf
    104     }
    105 }
    106 
    107 impl<const N: usize> Default for Buf<N> {
    108     fn default() -> Self {
    109         Self::new()
    110     }
    111 }