sigma_protocol_fiat_shamir - [devnet]
此内容尚不支持你的语言。
use 0x1::aptos_hash;use 0x1::bcs;use 0x1::option;use 0x1::ristretto255;use 0x1::sigma_protocol_statement;use 0x1::string;use 0x1::type_info;use 0x1::vector;Enum DomainSeparator
A domain separator prevents replay attacks in protocols and consists of 5 things.
-
The contract address (defense in depth: binds the proof to a specific deployed contract)
-
The chain ID (defense in depth: binds the proof to a specific Aptos network)
-
A protocol identifier, which is typically split up into two things:
- A higher-level protocol: “Confidential Assets v1 on Aptos”
- A lower-level relation identifier (e.g., “PedEq”, “Schnorr”, “DLEQ”, etc.)
- Statement (i.e., the public statement in the NP relation being proved)
- This is captured implicitly in our
proveandverifyfunctions ==> it is not part of this struct.
- Session identifier
- Chosen by user
- specifies the “context” in which this proof is valid
- e.g., “Alice (0x1) is paying Bob (0x2) at time
t - together with the protocol identifier, prevents replay attacks across the same protocol or different protocols
Note: The session identifier can be tricky, since in some settings the “session” accumulates implicitly in the statement being proven. For confidential assets, it does not AFAICT: the “session” is represented at least by the confidential balances of the users & their addresses.
enum DomainSeparator has copy, dropVariants
Constants
One of our internal invariants was broken. There is likely a logical error in the code.
const E_INTERNAL_INVARIANT_FAILED: u64 = 2;The length of the A field in Proof should NOT be zero
const E_PROOF_COMMITMENT_EMPTY: u64 = 1;Structs
FiatShamirInputs
Unfortunately, we cannot directly use the Statement struct here because its vector<RistrettoPoint>
will not serialize correctly via bcs::to_bytes, since a RistrettoPoint stores a Move VM “handle” rather than
an actual point.
struct FiatShamirInputs has dropFields
-
dst: sigma_protocol_fiat_shamir::DomainSeparator -
type_name: string::String -
The fully-qualified type name of the phantom marker type
PinStatement<P>. E.g.,"0x7::sigma_protocol_registration::Registration". This binds the Fiat-Shamir challenge to the specific protocol type for defense in depth. -
k: u64 -
stmt_X: vector<ristretto255::CompressedRistretto> -
stmt_x: vector<ristretto255::Scalar> -
proof_A: vector<ristretto255::CompressedRistretto>
Functions
new_domain_separator
public(friend) fun new_domain_separator(contract_address: address, chain_id: u8, protocol_id: vector<u8>, session_id: vector<u8>): sigma_protocol_fiat_shamir::DomainSeparatorImplementation
public(friend) fun new_domain_separator(contract_address: address, chain_id: u8, protocol_id: vector<u8>, session_id: vector<u8>): DomainSeparator { DomainSeparator::V1 { contract_address, chain_id, protocol_id, session_id }}fiat_shamir
Returns the Sigma protocol challenge and
public(friend) fun fiat_shamir<P>(dst: sigma_protocol_fiat_shamir::DomainSeparator, stmt: &sigma_protocol_statement::Statement<P>, compressed_A: &vector<ristretto255::CompressedRistretto>, k: u64): (ristretto255::Scalar, vector<ristretto255::Scalar>)Implementation
public(friend) fun fiat_shamir<P>( dst: DomainSeparator, stmt: &Statement<P>, compressed_A: &vector<CompressedRistretto>, k: u64): (Scalar, vector<Scalar>){ let m = compressed_A.length(); assert!(m != 0, error::invalid_argument(E_PROOF_COMMITMENT_EMPTY));
// We will hash an application-specific domain separator and the (full) public statement, // which will include any public parameters like group generators $G$, $H$.
// Note: A hardcodes $m$, the statement hardcodes $n_1$ and $n_2$, and $k$ is specified manually! let fs_inputs = FiatShamirInputs { dst, type_name: type_info::type_name<P>(), k, stmt_X: *stmt.get_compressed_points(), stmt_x: *stmt.get_scalars(), proof_A: *compressed_A };
let seed = sha2_512_value(&fs_inputs);
// Note:A more principled `Merlin` / `spongefish`-like approach would have been preferred, but... more code. // // e = SHA2-512(SHA2-512(fs_inputs.to_bcs_bytes()) || 0x00) seed.push_back(0u8); assert!(*seed.last() == 0, error::internal(E_INTERNAL_INVARIANT_FAILED)); let e_hash = sha2_512(seed);
// beta = SHA2-512(SHA2-512(fs_inputs.to_bcs_bytes()) || 0x01) *seed.last_mut() += 1; assert!(*seed.last() == 1, error::internal(E_INTERNAL_INVARIANT_FAILED)); let beta_hash = sha2_512(seed);
let e = new_scalar_uniform_from_64_bytes(e_hash).extract(); let beta = new_scalar_uniform_from_64_bytes(beta_hash).extract();
let betas = vector[]; let prev_beta = scalar_one(); betas.push_back(prev_beta); for (_i in 1..m) { prev_beta = prev_beta.scalar_mul(&beta); betas.push_back(prev_beta); };
// This will only fail when our logic above for generating the `\beta_i`'s is broken assert!(betas.length() == m, error::internal(E_INTERNAL_INVARIANT_FAILED));
(e, betas)}