Skip to content

Commit 1bead82

Browse files
committed
feat: keygen function
Signed-off-by: pedro bufulin <pedro@semiotic.ai>
1 parent cd6bb18 commit 1bead82

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

h2s2/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ ark-bn254 = { workspace = true}
2121
blake2 = {workspace = true}
2222
rayon = { workspace = true}
2323
digest = { workspace = true}
24+
once_cell = "1.20.2"

h2s2/src/holographic_homomorphic_signature_scheme.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ pub trait HolographicHomomorphicSignatureScheme<P: Pairing, D: Digest + Send + S
1515
fn setup<R: Rng>(rng: &mut R, n: usize) -> Result<Self::Parameters, Box<dyn Error>>;
1616

1717
/// Generate hash aggregate (H_a) with `tag` and `n` lanes
18-
fn precompute(tag: &[u8], n: usize) -> Result<P::G1, Box<dyn Error>>;
18+
/// the `tag` is supposed to be the allocation_id
19+
/// We can also generate the allocation_id with a scalar field:
20+
fn precompute(pp: &Self::Parameters, tag: &[u8], n: usize) -> Result<P::G1, Box<dyn Error>>;
1921

2022
/// Generate private and public receipt keys using `pp` parameters from `setup`
2123
fn keygen<R: Rng>(

h2s2/src/nc1.rs

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
use std::{error::Error, marker::PhantomData, ops::MulAssign};
1+
use std::ops::Mul;
2+
use std::{error::Error, marker::PhantomData};
23

34
use crate::holographic_homomorphic_signature_scheme::HolographicHomomorphicSignatureScheme;
45
use ark_bn254::{G1Projective, G2Projective};
56
use ark_ec::pairing::Pairing;
67
use ark_ec::AffineRepr;
8+
use ark_ff::PrimeField;
79
use ark_ff::{BigInteger, UniformRand, Zero};
810
use ark_std::rand::Rng;
911
use digest::Digest;
1012

1113
pub struct NC1<P: Pairing, D: Digest> {
14+
parameters: Option<H2S2Parameters<P>>,
1215
_pairing: PhantomData<P>,
1316
_hash: PhantomData<D>,
1417
}
1518

1619
pub struct H2S2Parameters<P: Pairing> {
1720
pub g1_generators: Vec<P::G1>,
1821
pub g2_generator: P::G2,
22+
// this public_key is the `u` param in the notes.
23+
// both the indexer and verifier need it. The secret key
24+
// remains with the gateway
1925
pub public_key: P::G2,
26+
pub secret_key: P::ScalarField,
2027
pub max_lanes: usize,
2128
}
2229

@@ -31,28 +38,72 @@ impl<P: Pairing, D: Digest + Send + Sync> HolographicHomomorphicSignatureScheme<
3138
type Weight = usize;
3239

3340
fn setup<R: Rng>(rng: &mut R, n: usize) -> Result<Self::Parameters, Box<dyn Error>> {
41+
// Generate the G2 generator
3442
let g2_generator = P::G2::rand(rng);
35-
println!("g2_generator, {:?}", g2_generator);
3643

37-
// Note that although max_lanes number of generators are specificied, we only use the first one in practice
38-
// All the other generators are used for security proofs
39-
Ok(H2S2Parameters {
40-
g1_generators: (0..=n).map(|_| P::G1::rand(rng)).collect(),
44+
// Prepare the parameters without the secret/public keys
45+
let g1_generators: Vec<P::G1> = (0..=n).map(|_| P::G1::rand(rng)).collect();
46+
let mut pp = H2S2Parameters {
47+
g1_generators,
4148
g2_generator,
42-
public_key: g2_generator.clone(),
43-
max_lanes: n, // Set max_lanes to the number of generators
44-
})
49+
secret_key: P::ScalarField::zero(), // Temporary placeholder
50+
public_key: P::G2::zero(), // Temporary placeholder
51+
max_lanes: n,
52+
};
53+
54+
// Use the keygen function to generate the secret/public key pair
55+
let (public_key, secret_key) = Self::keygen(&pp, rng)?;
56+
57+
// Update the parameters with the generated keys
58+
pp.secret_key = secret_key;
59+
pp.public_key = public_key;
60+
61+
Ok(pp)
4562
}
4663

47-
fn precompute(tag: &[u8], n: usize) -> Result<P::G1, Box<dyn Error>> {
48-
Ok(P::G1::default())
64+
//TODO: allocationn_ids (tag in this case) must be unpredictable
65+
// some random value has to be appended during initialization, prior
66+
// to the precompute in this function
67+
fn precompute(pp: &Self::Parameters, tag: &[u8], n: usize) -> Result<P::G1, Box<dyn Error>> {
68+
use ark_std::vec::Vec;
69+
70+
// Initialize the hash aggregate
71+
let mut hash_aggregate = P::G1::zero();
72+
73+
// Iterate through the lane IDs from 1 to N
74+
for lane_id in 1..=n {
75+
//TODO: in the original, the allocation_id is a random value from
76+
// the ScalarField. What is different here from using the u8 slice?
77+
// let allocation_id = P::Fr::rand(rng);
78+
79+
// Concatenate the tag (allocationId) with the lane ID
80+
let mut input = Vec::from(tag);
81+
input.extend_from_slice(&lane_id.to_le_bytes());
82+
83+
// Hash the concatenated input to generate a scalar value
84+
let hash_scalar = P::ScalarField::from_le_bytes_mod_order(D::digest(&input).as_ref());
85+
86+
// Map the scalar to a G1 element
87+
let hash_point = pp.g1_generators[0].mul(hash_scalar);
88+
89+
// Add the resulting point to the hash aggregate
90+
hash_aggregate += hash_point;
91+
}
92+
93+
Ok(hash_aggregate)
4994
}
5095

5196
fn keygen<R: Rng>(
5297
pp: &Self::Parameters,
5398
rng: &mut R,
5499
) -> Result<(Self::PublicKey, Self::SecretKey), Box<dyn Error>> {
55-
Ok((P::G2::rand(rng), P::ScalarField::rand(rng)))
100+
// Generate the private key as a random scalar
101+
let secret_key = P::ScalarField::rand(rng);
102+
103+
// Compute the public key as the secret_key multiplied by the G2 generator
104+
let public_key = pp.g2_generator.mul(secret_key);
105+
106+
Ok((public_key, secret_key))
56107
}
57108

58109
fn sign(
@@ -101,15 +152,39 @@ mod tests {
101152
use ark_bn254::Bn254;
102153
use ark_std::test_rng;
103154
use blake2::Blake2b512; // Use 512-bit Blake2b for digest
155+
use once_cell::sync::Lazy;
156+
157+
static N: usize = 10; // Define the number of generators
158+
159+
static PARAMS: Lazy<H2S2Parameters<Bn254>> = Lazy::new(|| {
160+
let mut rng = test_rng();
161+
NC1::<Bn254, Blake2b512>::setup(&mut rng, N).expect("Setup failed")
162+
});
104163

105164
#[test]
106165
fn test_setup() {
107-
let mut rng = test_rng();
108-
let n = 10; // Define the number of generators
109-
//TODO: figure what OutSize of Blake2b we should use. Is 512 OK?
110-
let params = NC1::<Bn254, Blake2b512>::setup(&mut rng, n).expect("Setup failed");
166+
let params = &*PARAMS;
167+
168+
assert_eq!(params.g1_generators.len(), 11); // n + 1
169+
assert_eq!(params.max_lanes, 10);
170+
171+
let expected_public_key = params.public_key;
172+
let calculated_public_key = params.g2_generator.mul(params.secret_key);
173+
174+
assert_eq!(
175+
calculated_public_key, expected_public_key,
176+
"Public key and private key relation is invalid!"
177+
);
178+
}
179+
180+
#[test]
181+
fn test_precompute() {
182+
let params = &*PARAMS;
183+
let allocation_id = b"example_allocation_id";
184+
185+
let hash_aggregate = NC1::<Bn254, Blake2b512>::precompute(&params, allocation_id, N)
186+
.expect("Precompute failed");
111187

112-
assert_eq!(params.g1_generators.len(), n + 1);
113-
assert_eq!(params.max_lanes, n);
188+
println!("Precomputed Hash Aggregate: {:?}", hash_aggregate);
114189
}
115190
}

0 commit comments

Comments
 (0)