1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3#![deny(missing_docs)]
4#![cfg_attr(not(feature = "std"), no_std)]
5#![allow(non_snake_case)]
6
7use core::fmt::Debug;
8use std_shims::io::{self, Read, Write};
9
10use zeroize::Zeroize;
11
12use curve25519_dalek::{traits::Identity, Scalar, EdwardsPoint};
13
14use monero_io::*;
15use monero_generators::H_pow_2;
16use monero_primitives::{keccak256_to_scalar, UnreducedScalar};
17
18#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
24struct BorromeanSignatures {
25 s0: [UnreducedScalar; 64],
26 s1: [UnreducedScalar; 64],
27 ee: Scalar,
28}
29
30impl BorromeanSignatures {
31 fn read<R: Read>(r: &mut R) -> io::Result<BorromeanSignatures> {
33 Ok(BorromeanSignatures {
34 s0: read_array(UnreducedScalar::read, r)?,
35 s1: read_array(UnreducedScalar::read, r)?,
36 ee: read_scalar(r)?,
37 })
38 }
39
40 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
42 for s0 in &self.s0 {
43 s0.write(w)?;
44 }
45 for s1 in &self.s1 {
46 s1.write(w)?;
47 }
48 write_scalar(&self.ee, w)
49 }
50
51 fn verify(&self, keys_a: &[EdwardsPoint], keys_b: &[EdwardsPoint]) -> bool {
52 let mut transcript = [0; 2048];
53
54 for i in 0 .. 64 {
55 #[allow(non_snake_case)]
56 let LL = EdwardsPoint::vartime_double_scalar_mul_basepoint(
57 &self.ee,
58 &keys_a[i],
59 &self.s0[i].ref10_slide_scalar_vartime(),
60 );
61 #[allow(non_snake_case)]
62 let LV = EdwardsPoint::vartime_double_scalar_mul_basepoint(
63 &keccak256_to_scalar(LL.compress().as_bytes()),
64 &keys_b[i],
65 &self.s1[i].ref10_slide_scalar_vartime(),
66 );
67 transcript[(i * 32) .. ((i + 1) * 32)].copy_from_slice(LV.compress().as_bytes());
68 }
69
70 keccak256_to_scalar(transcript) == self.ee
71 }
72}
73
74#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
76pub struct BorromeanRange {
77 sigs: BorromeanSignatures,
78 bit_commitments: [EdwardsPoint; 64],
79}
80
81impl BorromeanRange {
82 pub fn read<R: Read>(r: &mut R) -> io::Result<BorromeanRange> {
84 Ok(BorromeanRange {
85 sigs: BorromeanSignatures::read(r)?,
86 bit_commitments: read_array(read_point, r)?,
87 })
88 }
89
90 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
92 self.sigs.write(w)?;
93 write_raw_vec(write_point, &self.bit_commitments, w)
94 }
95
96 #[must_use]
98 pub fn verify(&self, commitment: &EdwardsPoint) -> bool {
99 if &self.bit_commitments.iter().sum::<EdwardsPoint>() != commitment {
100 return false;
101 }
102
103 #[allow(non_snake_case)]
104 let H_pow_2 = H_pow_2();
105 let mut commitments_sub_one = [EdwardsPoint::identity(); 64];
106 for i in 0 .. 64 {
107 commitments_sub_one[i] = self.bit_commitments[i] - H_pow_2[i];
108 }
109
110 self.sigs.verify(&self.bit_commitments, &commitments_sub_one)
111 }
112}