sigma_protocol_key_rotation - [devnet]
此内容尚不支持你的语言。
The key rotation NP relation ()
A ZKPoK of having rotated an encryption key to a new one and re-encrypted (part of) a Twisted ElGamal ciphertext.
Notation
- denotes a stale/old ciphertext component; denotes a fresh/new one.
- : number of available balance chunks.
The relation
\mathcal{R}_\mathsf{keyrot}^\ell\left(\begin{array}{l} H, \mathsf{ek}, \new{\mathsf{ek}}, \old{\mathbf{R}}, \new{\mathbf{R}} \textbf{;}\\ \mathsf{dk}, \delta, \delta_\mathsf{inv} \end{array}\right) = 1 \Leftrightarrow \left\{\begin{array}{r@{\,\,}l@{\quad}l} H &= \mathsf{dk} \cdot \mathsf{ek}\\ \new{\mathsf{ek}} &= \delta \cdot \mathsf{ek}\\ \mathsf{ek} &= \delta_\mathsf{inv} \cdot \new{\mathsf{ek}}\\ \new{R}_i &= \delta \cdot \old{R}_i, &\forall i \in [\ell]\\ \end{array}\right.Homomorphism
This can be framed as a homomorphism check where is the witness and is the statement.
- The homomorphism is:
- The transformation function is:
use 0x1::bcs;use 0x1::chain_id;use 0x1::error;use 0x1::fungible_asset;use 0x1::object;use 0x1::ristretto255;use 0x1::sigma_protocol_fiat_shamir;use 0x1::sigma_protocol_proof;use 0x1::sigma_protocol_representation;use 0x1::sigma_protocol_representation_vec;use 0x1::sigma_protocol_statement;use 0x1::sigma_protocol_statement_builder;use 0x1::sigma_protocol_utils;use 0x1::sigma_protocol_witness;use 0x1::signer;use 0x1::vector;Constants
The homomorphism or transformation function implementation is not inserting points at the expected positions.
const E_STATEMENT_BUILDER_INCONSISTENCY: u64 = 6;Index of (old decryption key) in the witness’s scalars vector.
const IDX_DK: u64 = 0;Index of (old encryption key) in the statement’s points vector.
const IDX_EK: u64 = 1;Index of in the statement’s points vector.
const IDX_H: u64 = 0;Protocol ID used for domain separation
const PROTOCOL_ID: vector<u8> = [65, 112, 116, 111, 115, 67, 111, 110, 102, 105, 100, 101, 110, 116, 105, 97, 108, 65, 115, 115, 101, 116, 47, 75, 101, 121, 82, 111, 116, 97, 116, 105, 111, 110, 86, 49];The key rotation proof was invalid
const E_INVALID_KEY_ROTATION_PROOF: u64 = 5;Index of in the witness’s scalars vector.
const IDX_DELTA: u64 = 1;Index of in the witness’s scalars vector.
const IDX_DELTA_INV: u64 = 2;Index of (new encryption key) in the statement’s points vector.
const IDX_EK_NEW: u64 = 2;The old R values ( ) occupy indices 3 to 3 + (num_chunks - 1), inclusive.
Note: The new R values () occupy indices 3 + num_chunks to 3 + (2*num_chunks - 1), inclusive.
A get_start_idx_for_new_R(num_chunks) function can be used to fetch the 3 + num_chunks starting index.
const START_IDX_OLD_R: u64 = 3;Structs
KeyRotation
Phantom marker type for key rotation statements.
struct KeyRotation has dropFields
-
dummy_field: bool
KeyRotationSession
Used for domain separation
struct KeyRotationSession has dropFields
-
sender: address -
token_type: object::Object<fungible_asset::Metadata> -
num_chunks: u64
Functions
get_start_idx_for_new_R
Returns the starting index of new_R values.
fun get_start_idx_for_new_R(): u64Implementation
inline fun get_start_idx_for_new_R(): u64 { START_IDX_OLD_R + get_num_available_chunks()}assert_key_rotation_statement_is_well_formed
Ensures the statement is of the form:
fun assert_key_rotation_statement_is_well_formed(stmt: &sigma_protocol_statement::Statement<sigma_protocol_key_rotation::KeyRotation>)Implementation
fun assert_key_rotation_statement_is_well_formed( stmt: &Statement<KeyRotation>,) { assert!(stmt.get_points().length() == 3 + 2 * get_num_available_chunks(), e_wrong_num_points()); assert!(stmt.get_scalars().length() == 0, e_wrong_num_scalars());}new_session
public(friend) fun new_session(sender: &signer, token_type: object::Object<fungible_asset::Metadata>): sigma_protocol_key_rotation::KeyRotationSessionImplementation
public(friend) fun new_session(sender: &signer, token_type: Object<Metadata>): KeyRotationSession { KeyRotationSession { sender: signer::address_of(sender), token_type, num_chunks: get_num_available_chunks(), }}new_key_rotation_statement
Creates a new key rotation statement. The order matches the NP relation: . Note that the # of chunks is inferred from the sizes of the old and new balance ciphertexts.
All points are decompressed internally from their compressed forms by the StatementBuilder.
@param compressed_ek: Compressed form of the old encryption key @param compressed_new_ek: Compressed form of the new encryption key @param compressed_old_R: Compressed forms of old_R (by reference; num_chunks elements) @param compressed_new_R: Compressed forms of new_R (by reference; num_chunks elements)
public(friend) fun new_key_rotation_statement(compressed_ek: ristretto255::CompressedRistretto, compressed_new_ek: ristretto255::CompressedRistretto, compressed_old_R: &vector<ristretto255::CompressedRistretto>, compressed_new_R: &vector<ristretto255::CompressedRistretto>): sigma_protocol_statement::Statement<sigma_protocol_key_rotation::KeyRotation>Implementation
public(friend) fun new_key_rotation_statement( compressed_ek: CompressedRistretto, compressed_new_ek: CompressedRistretto, compressed_old_R: &vector<CompressedRistretto>, compressed_new_R: &vector<CompressedRistretto>,): Statement<KeyRotation> { let err = error::internal(E_STATEMENT_BUILDER_INCONSISTENCY); let b = new_builder(); assert!(b.add_point(get_encryption_key_basepoint_compressed()) == IDX_H, err); // H assert!(b.add_point(compressed_ek) == IDX_EK, err); // ek assert!(b.add_point(compressed_new_ek) == IDX_EK_NEW, err); // new_ek assert!(b.add_points(compressed_old_R) == START_IDX_OLD_R, err); // old_R assert!(b.add_points(compressed_new_R) == START_IDX_OLD_R + get_num_available_chunks(), err); // new_R let stmt = b.build(); assert_key_rotation_statement_is_well_formed(&stmt); stmt}psi
The homomorphism for the key rotation relation.
Given witness , outputs:
[dk * ek, // should equal Hdelta * ek, // should equal new_ekdelta_inv * new_ek, // should equal ekdelta * old_R_i, // should equal new_R_i, for i in [1..num_chunks]]fun psi(_stmt: &sigma_protocol_statement::Statement<sigma_protocol_key_rotation::KeyRotation>, w: &sigma_protocol_witness::Witness): sigma_protocol_representation_vec::RepresentationVecImplementation
fun psi(_stmt: &Statement<KeyRotation>, w: &Witness): RepresentationVec { // WARNING: Crucial for security assert_key_rotation_statement_is_well_formed(_stmt); // WARNING: Crucial for security assert!(w.length() == 3, e_wrong_witness_len());
let dk = *w.get(IDX_DK); let delta = *w.get(IDX_DELTA); let delta_inv = *w.get(IDX_DELTA_INV);
// Build the representation vector let reprs = vector[ // dk * ek repr_scaled(IDX_EK, dk), // delta * ek repr_scaled(IDX_EK, delta), // delta_inv * new_ek repr_scaled(IDX_EK_NEW, delta_inv), ];
// delta * old_R_i for each chunk let ell = get_num_available_chunks(); reprs.append(vector::range(0, ell).map(|i| repr_scaled(START_IDX_OLD_R + i, delta) ));
// WARNING: Crucial for security assert!(reprs.length() == 3 + ell, e_wrong_output_len()); new_representation_vec(reprs)}f
The transformation function for the key rotation relation.
Given the statement, outputs:
[H,new_ek,ek,new_R_i for i in [1..num_chunks]]fun f(_stmt: &sigma_protocol_statement::Statement<sigma_protocol_key_rotation::KeyRotation>): sigma_protocol_representation_vec::RepresentationVecImplementation
fun f(_stmt: &Statement<KeyRotation>): RepresentationVec { // WARNING: We do not re-assert the stmt is well-formed anymore here, since wherever the transformation function // is called, so is the homomorphism, so the check will be done.
let ell = get_num_available_chunks(); let idx_r_new_start = get_start_idx_for_new_R();
let reprs = vector[ // H repr_point(IDX_H), // new_ek repr_point(IDX_EK_NEW), // ek repr_point(IDX_EK), ];
// new_R_i for each chunk reprs.append(vector::range(0, ell).map(|i| repr_point(idx_r_new_start + i) ));
// Note: Not needed for security, since a mismatched f(X) length will be caught in the verifier. But good practice // for catching mistakes *early* when implementing your f(X). assert!(reprs.length() == 3 + ell, e_wrong_output_len()); new_representation_vec(reprs)}assert_verifies
Asserts that a key rotation proof verifies
public(friend) fun assert_verifies(self: &sigma_protocol_key_rotation::KeyRotationSession, stmt: &sigma_protocol_statement::Statement<sigma_protocol_key_rotation::KeyRotation>, proof: &sigma_protocol_proof::Proof)Implementation
public(friend) fun assert_verifies(self: &KeyRotationSession, stmt: &Statement<KeyRotation>, proof: &Proof) { assert_key_rotation_statement_is_well_formed(stmt);
let success = sigma_protocol::verify( new_domain_separator(@aptos_framework, chain_id::get(), PROTOCOL_ID, bcs::to_bytes(self)), |_X, w| psi(_X, w), |_X| f(_X), stmt, proof );
assert!(success, error::invalid_argument(E_INVALID_KEY_ROTATION_PROOF));}