Skip to content

Commit 954ed67

Browse files
authored
Add signature and key abstraction for anoncreds (#17)
* add in signature abstraction Signed-off-by: Michael Lodder <[email protected]> * add traits for abstraction Signed-off-by: Michael Lodder <[email protected]> * fix test issues Signed-off-by: Michael Lodder <[email protected]> * lint fix Signed-off-by: Michael Lodder <[email protected]> --------- Signed-off-by: Michael Lodder <[email protected]>
1 parent 48f7136 commit 954ed67

15 files changed

+351
-109
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ serde_json = "1"
1818
serde_regex = "1"
1919
sha2 = "0.10"
2020
sha3 = "0.10"
21-
blsful = "2.4"
22-
subtle = "2.4.1"
21+
blsful = "2.5"
22+
subtle = "2.5"
2323
uint-zigzag = { version = "0.2", features = ["std"] }
2424
zeroize = "1"
2525
log = "0.4.20"

src/knox/ps/blind_signature.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use super::{SecretKey, Signature};
1+
use super::{PublicKey, SecretKey, Signature};
2+
use crate::knox::short_group_sig_core::short_group_traits::BlindSignature as BlindSignatureTrait;
23
use crate::CredxResult;
34
use blsful::inner_types::{G1Projective, Scalar};
45
use serde::{Deserialize, Serialize};
@@ -14,6 +15,24 @@ use subtle::CtOption;
1415
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
1516
pub struct BlindSignature(pub(crate) Signature);
1617

18+
impl BlindSignatureTrait for BlindSignature {
19+
type SecretKey = SecretKey;
20+
type PublicKey = PublicKey;
21+
type Signature = Signature;
22+
23+
fn new(
24+
commitment: G1Projective,
25+
sk: &SecretKey,
26+
msgs: &[(usize, Scalar)],
27+
) -> CredxResult<Self> {
28+
Self::new(commitment, sk, msgs)
29+
}
30+
31+
fn to_unblinded(self, blinding: Scalar) -> Signature {
32+
self.to_unblinded(blinding)
33+
}
34+
}
35+
1736
impl BlindSignature {
1837
/// The size of the signature in bytes
1938
pub const BYTES: usize = 128;

src/knox/ps/pok_signature.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::{PokSignatureProof, PublicKey, Signature};
2-
use crate::knox::short_group_sig_core::*;
2+
use crate::knox::short_group_sig_core::{
3+
short_group_traits::ProofOfSignatureKnowledgeContribution, *,
4+
};
35
use crate::CredxResult;
46
use blsful::inner_types::{ff::Field, group::Curve, G1Projective, G2Affine, G2Projective, Scalar};
57
use merlin::Transcript;
@@ -15,9 +17,13 @@ pub struct PokSignature {
1517
sigma_2: G1Projective,
1618
}
1719

18-
impl PokSignature {
20+
impl ProofOfSignatureKnowledgeContribution for PokSignature {
21+
type Signature = Signature;
22+
type PublicKey = PublicKey;
23+
type ProofOfKnowledge = PokSignatureProof;
24+
1925
/// Creates the initial proof data before a Fiat-Shamir calculation
20-
pub fn init(
26+
fn commit(
2127
signature: Signature,
2228
public_key: &PublicKey,
2329
messages: &[ProofMessage<Scalar>],
@@ -73,7 +79,7 @@ impl PokSignature {
7379
}
7480

7581
/// Convert the committed values to bytes for the fiat-shamir challenge
76-
pub fn add_proof_contribution(&mut self, transcript: &mut Transcript) {
82+
fn add_proof_contribution(&self, transcript: &mut Transcript) {
7783
transcript.append_message(
7884
b"sigma_1",
7985
self.sigma_1.to_affine().to_compressed().as_ref(),
@@ -91,7 +97,7 @@ impl PokSignature {
9197
}
9298

9399
/// Generate the Schnorr challenges for the selective disclosure proofs
94-
pub fn generate_proof(self, challenge: Scalar) -> CredxResult<PokSignatureProof> {
100+
fn generate_proof(self, challenge: Scalar) -> CredxResult<PokSignatureProof> {
95101
let proof = self
96102
.proof
97103
.generate_proof(challenge, self.secrets.as_ref())?;

src/knox/ps/pok_signature_proof.rs

Lines changed: 92 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::PublicKey;
22
use crate::error::Error;
3+
use crate::knox::short_group_sig_core::short_group_traits::ProofOfSignatureKnowledge;
34
use crate::CredxResult;
45
use blsful::inner_types::{group::prime::PrimeCurveAffine, *};
56
use core::convert::TryFrom;
@@ -17,80 +18,11 @@ pub struct PokSignatureProof {
1718
pub(crate) proof: Vec<Scalar>,
1819
}
1920

20-
impl PokSignatureProof {
21-
/// Store the proof as a sequence of bytes
22-
/// Each point is compressed to big-endian format
23-
/// Needs (N + 2) * 32 + 48 * 2 + 96 space otherwise it will panic
24-
/// where N is the number of hidden messages
25-
pub fn to_bytes(&self) -> Vec<u8> {
26-
let mut buffer = Vec::new();
27-
buffer.extend_from_slice(&self.sigma_1.to_affine().to_compressed());
28-
buffer.extend_from_slice(&self.sigma_2.to_affine().to_compressed());
29-
buffer.extend_from_slice(&self.commitment.to_affine().to_compressed());
30-
31-
for m in &self.proof {
32-
buffer.extend_from_slice(m.to_be_bytes().as_ref());
33-
}
34-
buffer
35-
}
36-
37-
/// Convert a byte sequence into the blind signature context
38-
/// Expected size is (N + 2) * 32 + 48 * 2 bytes
39-
pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Option<Self> {
40-
const SIZE: usize = 32 * 3 + 48 * 4;
41-
let buffer = bytes.as_ref();
42-
if buffer.len() < SIZE {
43-
return None;
44-
}
45-
if buffer.len() % 32 != 0 {
46-
return None;
47-
}
48-
49-
let hid_msg_cnt = (buffer.len() - 48 * 4) / 32;
50-
let mut offset = 48;
51-
let mut end = 96;
52-
let sigma_1 = G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[..offset]).unwrap())
53-
.map(G1Projective::from);
54-
let sigma_2 =
55-
G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[offset..end]).unwrap())
56-
.map(G1Projective::from);
57-
offset = end;
58-
end += 96;
59-
let commitment =
60-
G2Affine::from_compressed(&<[u8; 96]>::try_from(&buffer[offset..end]).unwrap())
61-
.map(G2Projective::from);
62-
63-
if sigma_1.is_none().unwrap_u8() == 1
64-
|| sigma_2.is_none().unwrap_u8() == 1
65-
|| commitment.is_none().unwrap_u8() == 1
66-
{
67-
return None;
68-
}
69-
70-
offset = end;
71-
end += 32;
72-
73-
let mut proof = Vec::new();
74-
for _ in 0..hid_msg_cnt {
75-
let c = Scalar::from_be_bytes(&<[u8; 32]>::try_from(&buffer[offset..end]).unwrap());
76-
offset = end;
77-
end = offset + 32;
78-
if c.is_none().unwrap_u8() == 1 {
79-
return None;
80-
}
81-
82-
proof.push(c.unwrap());
83-
}
84-
Some(Self {
85-
sigma_1: sigma_1.unwrap(),
86-
sigma_2: sigma_2.unwrap(),
87-
commitment: commitment.unwrap(),
88-
proof,
89-
})
90-
}
21+
impl ProofOfSignatureKnowledge for PokSignatureProof {
22+
type PublicKey = PublicKey;
9123

9224
/// Convert the committed values to bytes for the fiat-shamir challenge
93-
pub fn add_challenge_contribution(
25+
fn add_proof_contribution(
9426
&self,
9527
public_key: &PublicKey,
9628
rvl_msgs: &[(usize, Scalar)],
@@ -140,7 +72,7 @@ impl PokSignatureProof {
14072
/// Validate the proof, only checks the signature proof
14173
/// the selective disclosure proof is checked by verifying
14274
/// self.challenge == computed_challenge
143-
pub fn verify(&self, rvl_msgs: &[(usize, Scalar)], public_key: &PublicKey) -> bool {
75+
fn verify(&self, rvl_msgs: &[(usize, Scalar)], public_key: &PublicKey) -> CredxResult<()> {
14476
// check the signature proof
14577
if self
14678
.sigma_1
@@ -149,22 +81,24 @@ impl PokSignatureProof {
14981
.unwrap_u8()
15082
== 1
15183
{
152-
return false;
84+
return Err(Error::General("Invalid proof - identity"));
15385
}
15486

15587
if public_key.y.len() < rvl_msgs.len() {
156-
return false;
88+
return Err(Error::General(
89+
"Invalid key - revealed messages length is bigger than the public key",
90+
));
15791
}
15892
if public_key.is_invalid().unwrap_u8() == 1u8 {
159-
return false;
93+
return Err(Error::General("Invalid public key"));
16094
}
16195

16296
let mut points = Vec::new();
16397
let mut scalars = Vec::new();
16498

16599
for (idx, msg) in rvl_msgs {
166100
if *idx > public_key.y.len() {
167-
return false;
101+
return Err(Error::General("Invalid proof - revealed message index"));
168102
}
169103
points.push(public_key.y[*idx]);
170104
scalars.push(*msg);
@@ -176,7 +110,7 @@ impl PokSignatureProof {
176110

177111
let j = G2Projective::sum_of_products(points.as_ref(), scalars.as_ref());
178112

179-
multi_miller_loop(&[
113+
let res = multi_miller_loop(&[
180114
(&self.sigma_1.to_affine(), &G2Prepared::from(j.to_affine())),
181115
(
182116
&self.sigma_2.to_affine(),
@@ -186,11 +120,16 @@ impl PokSignatureProof {
186120
.final_exponentiation()
187121
.is_identity()
188122
.unwrap_u8()
189-
== 1
123+
== 1;
124+
if res {
125+
Ok(())
126+
} else {
127+
Err(Error::General("Invalid proof - signature proof"))
128+
}
190129
}
191130

192131
/// Return the Schnorr proofs for all hidden messages
193-
pub fn get_hidden_message_proofs(
132+
fn get_hidden_message_proofs(
194133
&self,
195134
public_key: &PublicKey,
196135
rvl_msgs: &[(usize, Scalar)],
@@ -218,3 +157,76 @@ impl PokSignatureProof {
218157
Ok(hidden)
219158
}
220159
}
160+
161+
impl PokSignatureProof {
162+
/// Store the proof as a sequence of bytes
163+
/// Each point is compressed to big-endian format
164+
/// Needs (N + 2) * 32 + 48 * 2 + 96 space otherwise it will panic
165+
/// where N is the number of hidden messages
166+
pub fn to_bytes(&self) -> Vec<u8> {
167+
let mut buffer = Vec::new();
168+
buffer.extend_from_slice(&self.sigma_1.to_affine().to_compressed());
169+
buffer.extend_from_slice(&self.sigma_2.to_affine().to_compressed());
170+
buffer.extend_from_slice(&self.commitment.to_affine().to_compressed());
171+
172+
for m in &self.proof {
173+
buffer.extend_from_slice(m.to_be_bytes().as_ref());
174+
}
175+
buffer
176+
}
177+
178+
/// Convert a byte sequence into the blind signature context
179+
/// Expected size is (N + 2) * 32 + 48 * 2 bytes
180+
pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Option<Self> {
181+
const SIZE: usize = 32 * 3 + 48 * 4;
182+
let buffer = bytes.as_ref();
183+
if buffer.len() < SIZE {
184+
return None;
185+
}
186+
if buffer.len() % 32 != 0 {
187+
return None;
188+
}
189+
190+
let hid_msg_cnt = (buffer.len() - 48 * 4) / 32;
191+
let mut offset = 48;
192+
let mut end = 96;
193+
let sigma_1 = G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[..offset]).unwrap())
194+
.map(G1Projective::from);
195+
let sigma_2 =
196+
G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[offset..end]).unwrap())
197+
.map(G1Projective::from);
198+
offset = end;
199+
end += 96;
200+
let commitment =
201+
G2Affine::from_compressed(&<[u8; 96]>::try_from(&buffer[offset..end]).unwrap())
202+
.map(G2Projective::from);
203+
204+
if sigma_1.is_none().unwrap_u8() == 1
205+
|| sigma_2.is_none().unwrap_u8() == 1
206+
|| commitment.is_none().unwrap_u8() == 1
207+
{
208+
return None;
209+
}
210+
211+
offset = end;
212+
end += 32;
213+
214+
let mut proof = Vec::new();
215+
for _ in 0..hid_msg_cnt {
216+
let c = Scalar::from_be_bytes(&<[u8; 32]>::try_from(&buffer[offset..end]).unwrap());
217+
offset = end;
218+
end = offset + 32;
219+
if c.is_none().unwrap_u8() == 1 {
220+
return None;
221+
}
222+
223+
proof.push(c.unwrap());
224+
}
225+
Some(Self {
226+
sigma_1: sigma_1.unwrap(),
227+
sigma_2: sigma_2.unwrap(),
228+
commitment: commitment.unwrap(),
229+
proof,
230+
})
231+
}
232+
}

src/knox/ps/prover.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{BlindSignatureContext, PokSignature, PublicKey, Signature};
2+
use crate::knox::short_group_sig_core::short_group_traits::ProofOfSignatureKnowledgeContribution;
23
use crate::knox::short_group_sig_core::*;
34
use crate::CredxResult;
45
use blsful::inner_types::{ff::Field, group::Curve, G1Affine, G1Projective, Scalar};
@@ -71,7 +72,7 @@ impl Prover {
7172
messages: &[ProofMessage<Scalar>],
7273
rng: impl RngCore + CryptoRng,
7374
) -> CredxResult<PokSignature> {
74-
PokSignature::init(signature, public_key, messages, rng)
75+
PokSignature::commit(signature, public_key, messages, rng)
7576
}
7677
}
7778

src/knox/ps/public_key.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
use super::SecretKey;
2+
use crate::{
3+
error::Error, knox::short_group_sig_core::short_group_traits::PublicKey as PublicKeyTrait,
4+
};
25
use blsful::inner_types::*;
36
use core::convert::TryFrom;
47
use serde::{Deserialize, Serialize};
@@ -49,6 +52,55 @@ impl From<&SecretKey> for PublicKey {
4952
}
5053
}
5154

55+
impl PublicKeyTrait for PublicKey {
56+
type MessageGenerator = G2Projective;
57+
type BlindMessageGenerator = G1Projective;
58+
}
59+
60+
impl From<PublicKey> for Vec<u8> {
61+
fn from(pk: PublicKey) -> Self {
62+
Self::from(&pk)
63+
}
64+
}
65+
66+
impl From<&PublicKey> for Vec<u8> {
67+
fn from(pk: &PublicKey) -> Self {
68+
pk.to_bytes()
69+
}
70+
}
71+
72+
impl TryFrom<Vec<u8>> for PublicKey {
73+
type Error = Error;
74+
75+
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
76+
Self::try_from(bytes.as_slice())
77+
}
78+
}
79+
80+
impl TryFrom<&Vec<u8>> for PublicKey {
81+
type Error = Error;
82+
83+
fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
84+
Self::try_from(bytes.as_slice())
85+
}
86+
}
87+
88+
impl TryFrom<&[u8]> for PublicKey {
89+
type Error = Error;
90+
91+
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
92+
Self::from_bytes(bytes).ok_or(Error::General("Invalid public key"))
93+
}
94+
}
95+
96+
impl TryFrom<Box<[u8]>> for PublicKey {
97+
type Error = Error;
98+
99+
fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
100+
Self::try_from(bytes.as_ref())
101+
}
102+
}
103+
52104
impl PublicKey {
53105
/// Check if this public key is valid
54106
pub fn is_valid(&self) -> Choice {

0 commit comments

Comments
 (0)