diff --git a/curdleproofs/curdleproofs/__init__.py b/curdleproofs/curdleproofs/__init__.py index 02cfade..1bfa3f1 100644 --- a/curdleproofs/curdleproofs/__init__.py +++ b/curdleproofs/curdleproofs/__init__.py @@ -1,6 +1,7 @@ from .whisk_interface import ( IsValidWhiskShuffleProof, IsValidWhiskOpeningProof, + GenerateWhiskShuffleProof, GenerateWhiskTrackerProof, ) from .opening import TrackerOpeningProof diff --git a/curdleproofs/curdleproofs/curdleproofs.py b/curdleproofs/curdleproofs/curdleproofs.py index 25d97df..c901e72 100644 --- a/curdleproofs/curdleproofs/curdleproofs.py +++ b/curdleproofs/curdleproofs/curdleproofs.py @@ -50,6 +50,7 @@ class CurdleProofsProof: def __init__( self, + M: PointProjective, A: PointProjective, cm_T: GroupCommitment, cm_U: GroupCommitment, @@ -59,6 +60,7 @@ def __init__( same_scalar_proof: SameScalarProof, same_msm_proof: SameMSMProof, ) -> None: + self.M = M self.A = A self.cm_T = cm_T self.cm_U = cm_U @@ -176,6 +178,7 @@ def new( ) return cls( + M=M, A=A, cm_T=cm_T, cm_U=cm_U, @@ -193,7 +196,6 @@ def verify( vec_S: List[PointAffine], vec_T: List[PointAffine], vec_U: List[PointAffine], - M: PointProjective, ) -> Tuple[bool, str]: ell = len(vec_R) @@ -206,7 +208,7 @@ def verify( transcript.append_list( b"curdleproofs_step1", points_affine_to_bytes(vec_R + vec_S + vec_T + vec_U) ) - transcript.append(b"curdleproofs_step1", point_projective_to_bytes(M)) + transcript.append(b"curdleproofs_step1", point_projective_to_bytes(self.M)) vec_a = transcript.get_and_append_challenges(b"curdleproofs_vec_a", ell) self.same_perm_proof.verify( @@ -216,7 +218,7 @@ def verify( crs_G_sum=crs.G_sum, crs_H_sum=crs.H_sum, A=self.A, - M=M, + M=self.M, vec_a=vec_a, n_blinders=N_BLINDERS, transcript=transcript, @@ -281,6 +283,7 @@ def verify( def to_json(self) -> str: dic = { + "M": point_projective_to_json(self.M), "A": point_projective_to_json(self.A), "cm_T": self.cm_T.to_json(), "cm_U": self.cm_U.to_json(), @@ -296,6 +299,7 @@ def to_json(self) -> str: def from_json(cls: Type[T_CurdleProofsProof], json_str: str) -> T_CurdleProofsProof: dic = json.loads(json_str) return cls( + M=point_projective_from_json(dic["M"]), A=point_projective_from_json(dic["A"]), cm_T=GroupCommitment.from_json(dic["cm_T"]), cm_U=GroupCommitment.from_json(dic["cm_U"]), diff --git a/curdleproofs/curdleproofs/test_curdleproofs.py b/curdleproofs/curdleproofs/test_curdleproofs.py index 611a40d..32ffe76 100644 --- a/curdleproofs/curdleproofs/test_curdleproofs.py +++ b/curdleproofs/curdleproofs/test_curdleproofs.py @@ -50,7 +50,9 @@ from curdleproofs.whisk_interface import ( WhiskTracker, GenerateWhiskTrackerProof, + GenerateWhiskShuffleProof, IsValidWhiskOpeningProof, + IsValidWhiskShuffleProof, ) @@ -636,6 +638,15 @@ def test_whisk_interface_tracker_opening_proof(): assert IsValidWhiskOpeningProof(tracker, k_commitment, tracker_proof) +def test_whisk_interface_shuffle_proof(): + N = 64 + ell = N - N_BLINDERS + crs = generate_random_crs(ell) + pre_trackers = generate_random_trackers(ell) + post_trackers, shuffle_proof = GenerateWhiskShuffleProof(crs, pre_trackers) + assert IsValidWhiskShuffleProof(crs, pre_trackers, post_trackers, shuffle_proof) + + def generate_random_k() -> Fr: return generate_blinders(1)[0] @@ -649,3 +660,11 @@ def generate_tracker(k: Fr) -> WhiskTracker: r_G = multiply(G1, int(r)) k_r_G = multiply(r_G, int(k)) return WhiskTracker(normalize(r_G), normalize(k_r_G)) + + +def generate_random_crs(ell: int) -> CurdleproofsCrs: + return CurdleproofsCrs.new(ell, N_BLINDERS) + + +def generate_random_trackers(n: int) -> List[WhiskTracker]: + return [generate_tracker(generate_random_k()) for _ in range(n)] diff --git a/curdleproofs/curdleproofs/whisk_interface.py b/curdleproofs/curdleproofs/whisk_interface.py index 60bf72e..c5ad838 100644 --- a/curdleproofs/curdleproofs/whisk_interface.py +++ b/curdleproofs/curdleproofs/whisk_interface.py @@ -1,6 +1,11 @@ +import random from typing import Container, Sequence, Tuple from curdleproofs.crs import CurdleproofsCrs -from curdleproofs.curdleproofs import N_BLINDERS, CurdleProofsProof +from curdleproofs.curdleproofs import ( + N_BLINDERS, + CurdleProofsProof, + shuffle_permute_and_commit_input, +) from curdleproofs.curdleproofs_transcript import CurdleproofsTranscript from curdleproofs.opening import TrackerOpeningProof from curdleproofs.util import ( @@ -8,7 +13,7 @@ affine_to_projective, Fr, ) -from py_ecc.optimized_bls12_381.optimized_curve import G1 +from py_ecc.optimized_bls12_381.optimized_curve import G1, normalize class WhiskTracker: @@ -24,28 +29,54 @@ def __init__(self, r_G: BLSG1Point, k_r_G: BLSG1Point): def IsValidWhiskShuffleProof( + crs: CurdleproofsCrs, pre_shuffle_trackers: Sequence[WhiskTracker], post_shuffle_trackers: Sequence[WhiskTracker], - M: BLSG1Point, shuffle_proof: SerializedCurdleProofsProof, ) -> Tuple[bool, str]: """ Verify `post_shuffle_trackers` is a permutation of `pre_shuffle_trackers`. """ - crs = CurdleproofsCrs.new(len(pre_shuffle_trackers), N_BLINDERS) - vec_R = [pre_shuffle_tracker.r_G for pre_shuffle_tracker in pre_shuffle_trackers] - vec_S = [pre_shuffle_tracker.k_r_G for pre_shuffle_tracker in pre_shuffle_trackers] + vec_R = [tracker.r_G for tracker in pre_shuffle_trackers] + vec_S = [tracker.k_r_G for tracker in pre_shuffle_trackers] - vec_T = [post_shuffle_tracker.r_G for post_shuffle_tracker in post_shuffle_trackers] - vec_U = [ - post_shuffle_tracker.k_r_G for post_shuffle_tracker in post_shuffle_trackers - ] + vec_T = [tracker.r_G for tracker in post_shuffle_trackers] + vec_U = [tracker.k_r_G for tracker in post_shuffle_trackers] shuffle_proof_instance = CurdleProofsProof.from_json(shuffle_proof.decode()) - M_projective = affine_to_projective(M) + return shuffle_proof_instance.verify(crs, vec_R, vec_S, vec_T, vec_U) + + +def GenerateWhiskShuffleProof( + crs: CurdleproofsCrs, pre_shuffle_trackers: Sequence[WhiskTracker] +) -> Tuple[Sequence[WhiskTracker], SerializedCurdleProofsProof]: + permutation = list(range(len(crs.vec_G))) + random.shuffle(permutation) + k = Fr(random.randint(1, Fr.field_modulus)) + + vec_R = [tracker.r_G for tracker in pre_shuffle_trackers] + vec_S = [tracker.k_r_G for tracker in pre_shuffle_trackers] + + vec_T, vec_U, M, vec_m_blinders = shuffle_permute_and_commit_input( + crs, vec_R, vec_S, permutation, k + ) + + shuffle_proof: CurdleProofsProof = CurdleProofsProof.new( + crs=crs, + vec_R=vec_R, + vec_S=vec_S, + vec_T=vec_T, + vec_U=vec_U, + M=M, + permutation=permutation, + k=k, + vec_m_blinders=vec_m_blinders, + ) + + post_trackers = [WhiskTracker(r_G, k_r_G) for r_G, k_r_G in zip(vec_T, vec_U)] - return shuffle_proof_instance.verify(crs, vec_R, vec_S, vec_T, vec_U, M_projective) + return post_trackers, shuffle_proof.to_json().encode() SerializedWhiskTrackerProof = bytes