scrypt
Créé en 2009 par Colin Percival•RFC 7914
💎 PIONNIER MEMORY-HARD - RÉSISTANCE ASIC PROUVÉE
scrypt révolutionna la cryptographie moderne en 2009 avec sa fonction memory-hard. Résistance GPU/ASIC démontrée par 13 années de crypto-monnaies (Litecoin, Dogecoin), protection équitable du mining et standard IETF RFC 7914.
Paramètres scrypt - Configuration Memory-Hard
| Paramètre | Description | Valeurs Typiques | Impact Sécurité |
|---|---|---|---|
| N | Coût CPU/mémoire | 2^14 à 2^20 | Résistance ASIC |
| r | Taille bloc | 8 (standard) | Usage mémoire |
| p | Parallélisme | 1-4 | Multi-threading |
| keylen | Longueur sortie | 32-64 bytes | Sécurité hash |
La consommation mémoire élevée est la clé de la résistance scrypt. N=32768, r=8 → 256 MiB minimum, rendant les attaques matérielles spécialisées coûteuses.
Adoption Crypto-monnaies - Succès Historique
| Crypto-monnaie | Configuration | Statut | Note |
|---|---|---|---|
| Litecoin (LTC) | N=1024, r=1, p=1 | Actif depuis 2011 | Premier succès |
| Dogecoin (DOGE) | N=1024, r=1, p=1 | Actif | Fork Litecoin |
| Vertcoin (VTC) | N=1024, r=1, p=1 | Actif | ASIC-resistant |
| Applications modernes | N=32768, r=8, p=1 | Recommandé | Haute sécurité |
Litecoin (2011) fut la première crypto-monnaie majeure à adopter scrypt, démocratisant le mining avec des GPU standard vs Bitcoin ASIC.
13 années de résistance prouvée aux ASIC miniers, maintenant l'équité du mining décentralisé.
Avantages Memory-Hard Function
Memory-Hard Function
MaximumCoût mémoire élevé (128×N×r bytes) rend les attaques GPU/ASIC économiquement non-viables
Résistance ASIC Prouvée
Excellent10+ années d'usage en crypto-monnaies, protection mineurs individuels démontrée
Paramètres Flexibles
ImportantConfiguration N, r, p adaptable selon besoins sécurité vs performance
Standard IETF RFC 7914
RéférenceSpécification officielle, implémentations interopérables multi-langages
Mécanismes de Résistance
- • Consommation RAM obligatoire (128×N×r)
- • Accès mémoire fréquents et aléatoires
- • Goulot d'étranglement bande passante
- • Coût matériel spécialisé prohibitif
- • Réduire RAM → augmenter calculs
- • Paramètres configurables N, r, p
- • Évolutivité selon hardware disponible
- • Équilibre sécurité/performance
Applications et Cas d'Usage
Crypto-monnaies
Applications Sécurisées
Enterprise Security
Recherche & R&D
Implémentations Memory-Hard Production
Implémentations complètes avec configurations adaptatives, benchmarks et simulation mining crypto-monnaie pour usage production.
Node.js - Manager scrypt Adaptatif
const crypto = require('crypto');
const scrypt = require('scrypt');
// ✅ SCRYPT - Configuration Production 2024
class ScryptManager {
constructor() {
// Configurations recommandées selon usage
this.configs = {
// Applications web interactives
interactive: {
N: 16384, // 2^14
r: 8, // Block size factor
p: 1, // Parallelization
keylen: 64, // Output length
memory: '128MB',
time: '~200ms'
},
// Services backend
server: {
N: 32768, // 2^15
r: 8,
p: 1,
keylen: 64,
memory: '256MB',
time: '~500ms'
},
// Haute sécurité (crypto-monnaies style)
high_security: {
N: 1048576, // 2^20
r: 8,
p: 1,
keylen: 64,
memory: '1GB',
time: '~5s'
}
};
}
// Hash avec scrypt (Node.js crypto natif)
async hashPassword(password, salt = null, config = 'server') {
const params = this.configs[config];
if (!salt) {
salt = crypto.randomBytes(32);
}
const startTime = Date.now();
try {
const derived = await new Promise((resolve, reject) => {
crypto.scrypt(password, salt, params.keylen, {
N: params.N,
r: params.r,
p: params.p,
maxmem: params.N * params.r * 128 * 2 // Sécurité mémoire
}, (err, derivedKey) => {
if (err) reject(err);
else resolve(derivedKey);
});
});
const duration = Date.now() - startTime;
return {
hash: derived.toString('hex'),
salt: salt.toString('hex'),
algorithm: 'scrypt',
params: params,
config: config,
duration: `${duration}ms`,
memory_usage: this.calculateMemoryUsage(params),
timestamp: new Date().toISOString()
};
} catch (error) {
throw new Error(`scrypt hashing failed: ${error.message}`);
}
}
// Vérification sécurisée
async verifyPassword(password, expectedHash, salt, config = 'server') {
try {
const result = await this.hashPassword(password, Buffer.from(salt, 'hex'), config);
// Comparaison temps constant
const expected = Buffer.from(expectedHash, 'hex');
const computed = Buffer.from(result.hash, 'hex');
return {
valid: crypto.timingSafeEqual(expected, computed),
algorithm: 'scrypt',
timing_safe: true,
config: config
};
} catch (error) {
return {
valid: false,
error: error.message,
algorithm: 'scrypt',
timing_safe: true
};
}
}
// Calcul usage mémoire
calculateMemoryUsage(params) {
const memoryBytes = 128 * params.N * params.r;
const memoryMB = memoryBytes / (1024 * 1024);
return {
bytes: memoryBytes,
mb: Math.round(memoryMB),
formula: `128 × ${params.N} × ${params.r} = ${memoryBytes} bytes`
};
}
// Benchmark pour optimiser paramètres
async benchmark(password = 'testpassword123', configs = ['interactive', 'server']) {
const results = {};
for (const configName of configs) {
const startTime = Date.now();
try {
const result = await this.hashPassword(password, null, configName);
const endTime = Date.now();
const totalTime = endTime - startTime;
results[configName] = {
...result,
total_duration: `${totalTime}ms`,
recommendation: this.getPerformanceRecommendation(totalTime)
};
} catch (error) {
results[configName] = {
error: error.message,
config: configName
};
}
}
return results;
}
getPerformanceRecommendation(duration) {
if (duration < 100) return '⚠️ Trop rapide - augmenter N';
if (duration < 300) return '✅ Optimal pour web interactif';
if (duration < 800) return '✅ Bon pour services backend';
if (duration < 2000) return '🔒 Haute sécurité acceptable';
return '🔒 Très sécurisé - vérifier ressources serveur';
}
// Configuration adaptative selon ressources système
getConfigForResources(availableRAM_MB, targetTime_ms = 300) {
// Calcul N optimal selon RAM disponible
let N = 16384; // Base
const r = 8;
while ((128 * N * r) / (1024 * 1024) < availableRAM_MB * 0.1 && N < 1048576) {
N *= 2;
}
return {
N: N,
r: r,
p: 1,
keylen: 64,
estimated_memory_mb: Math.round((128 * N * r) / (1024 * 1024)),
estimated_time: 'Variable selon CPU'
};
}
}
// Usage Production
const scryptManager = new ScryptManager();
// Hash sécurisé
(async () => {
const password = 'MonMotDePasseSecurise2024!';
// Hash avec configuration serveur
const hashResult = await scryptManager.hashPassword(password, null, 'server');
console.log('Hash Result:', hashResult);
// Vérification
const verification = await scryptManager.verifyPassword(
password,
hashResult.hash,
hashResult.salt,
'server'
);
console.log('Verification:', verification);
// Benchmark performance
const benchmark = await scryptManager.benchmark();
console.log('Benchmark:', benchmark);
// Configuration adaptative
const adaptiveConfig = scryptManager.getConfigForResources(4096); // 4GB RAM
console.log('Adaptive Config:', adaptiveConfig);
})();Python - Configuration Multi-Niveaux
import hashlib
import scrypt # pip install scrypt
import secrets
import time
from typing import Dict, Optional, Tuple
class ScryptManager:
"""Manager scrypt optimisé pour production Python"""
def __init__(self):
# Configurations standard
self.configs = {
'interactive': {
'N': 2**14, # 16384
'r': 8,
'p': 1,
'keylen': 64,
'memory_mb': 128,
'target_time': 200
},
'server': {
'N': 2**15, # 32768
'r': 8,
'p': 1,
'keylen': 64,
'memory_mb': 256,
'target_time': 500
},
'high_security': {
'N': 2**18, # 262144
'r': 8,
'p': 1,
'keylen': 64,
'memory_mb': 2048,
'target_time': 2000
}
}
def hash_password(self, password: str, salt: bytes = None, config: str = 'server') -> Dict:
"""Hash avec scrypt memory-hard"""
if salt is None:
salt = secrets.token_bytes(32)
params = self.configs[config]
start_time = time.perf_counter()
try:
# Hash scrypt
derived = scrypt.hash(
password=password.encode('utf-8'),
salt=salt,
N=params['N'],
r=params['r'],
p=params['p'],
buflen=params['keylen']
)
duration = (time.perf_counter() - start_time) * 1000
return {
'hash': derived.hex(),
'salt': salt.hex(),
'algorithm': 'scrypt',
'params': {
'N': params['N'],
'r': params['r'],
'p': params['p'],
'keylen': params['keylen']
},
'config': config,
'duration_ms': round(duration),
'memory_usage': self._calculate_memory_usage(params),
'timestamp': time.time()
}
except Exception as e:
raise Exception(f"scrypt hashing failed: {e}")
def verify_password(self, password: str, hash_hex: str, salt_hex: str, config: str = 'server') -> Dict:
"""Vérification sécurisée temps constant"""
start_time = time.perf_counter()
try:
# Reconstruction du hash
salt = bytes.fromhex(salt_hex)
result = self.hash_password(password, salt, config)
# Comparaison sécurisée
expected = bytes.fromhex(hash_hex)
computed = bytes.fromhex(result['hash'])
is_valid = secrets.compare_digest(expected, computed)
duration = (time.perf_counter() - start_time) * 1000
return {
'valid': is_valid,
'algorithm': 'scrypt',
'config': config,
'duration_ms': round(duration),
'timing_safe': True
}
except Exception:
# Maintenir temps constant même en cas d'erreur
time.sleep(0.1)
return {
'valid': False,
'algorithm': 'scrypt',
'timing_safe': True,
'error': 'Verification failed'
}
def benchmark_configs(self, test_password: str = 'benchmark123') -> Dict:
"""Benchmark des configurations disponibles"""
results = {}
for config_name in self.configs.keys():
try:
start_time = time.perf_counter()
result = self.hash_password(test_password, config=config_name)
total_time = (time.perf_counter() - start_time) * 1000
results[config_name] = {
'duration_ms': round(total_time),
'memory_mb': result['memory_usage']['mb'],
'params': result['params'],
'recommendation': self._get_recommendation(total_time),
'memory_hard_score': self._calculate_memory_hard_score(result['params'])
}
except Exception as e:
results[config_name] = {'error': str(e)}
return results
def _calculate_memory_usage(self, params: Dict) -> Dict:
"""Calcul précis usage mémoire scrypt"""
# Formule scrypt: 128 * N * r bytes
memory_bytes = 128 * params['N'] * params['r']
memory_mb = memory_bytes / (1024 * 1024)
return {
'bytes': memory_bytes,
'mb': round(memory_mb),
'formula': f"128 × {params['N']} × {params['r']} = {memory_bytes:,} bytes"
}
def _calculate_memory_hard_score(self, params: Dict) -> str:
"""Score résistance matériel spécialisé"""
memory_mb = (128 * params['N'] * params['r']) / (1024 * 1024)
if memory_mb >= 1024:
return "EXCELLENT - Résistance ASIC maximale"
elif memory_mb >= 512:
return "TRÈS BON - Résistance GPU/ASIC élevée"
elif memory_mb >= 128:
return "BON - Résistance GPU correcte"
else:
return "INSUFFISANT - Augmenter paramètre N"
def _get_recommendation(self, duration_ms: float) -> str:
"""Recommandations basées sur performance"""
if duration_ms < 50:
return "⚠️ Très rapide - paramètres faibles"
elif duration_ms < 200:
return "✅ Optimal pour applications interactives"
elif duration_ms < 600:
return "✅ Bon pour services backend"
elif duration_ms < 1500:
return "🔒 Haute sécurité - acceptable"
else:
return "🔒 Très sécurisé - impact performance significatif"
def estimate_config_for_target(self, target_time_ms: int, max_memory_mb: int) -> Dict:
"""Estimation configuration pour temps et mémoire cibles"""
# Partir d'une base et ajuster
N = 16384 # Base 2^14
r = 8
p = 1
# Ajuster N selon contraintes mémoire
while (128 * N * r) / (1024 * 1024) <= max_memory_mb and N < 2**20:
N *= 2
# Si on a dépassé la limite mémoire, revenir en arrière
if (128 * N * r) / (1024 * 1024) > max_memory_mb:
N //= 2
estimated_memory = (128 * N * r) / (1024 * 1024)
return {
'N': N,
'r': r,
'p': p,
'keylen': 64,
'estimated_memory_mb': round(estimated_memory),
'max_memory_mb': max_memory_mb,
'target_time_ms': target_time_ms,
'note': 'Temps réel peut varier selon CPU'
}
# Usage Production
if __name__ == "__main__":
manager = ScryptManager()
# Test complet
password = "MotDePasseSecurise2024!"
# Hash
hash_result = manager.hash_password(password, config='server')
print(f"Hash Result: {hash_result}")
# Vérification
verify_result = manager.verify_password(
password,
hash_result['hash'],
hash_result['salt'],
'server'
)
print(f"Verification: {verify_result}")
# Benchmark
benchmark = manager.benchmark_configs()
print("\nBenchmark Results:")
for config, result in benchmark.items():
print(f" {config}: {result}")
# Configuration optimisée
optimal = manager.estimate_config_for_target(300, 512) # 300ms, 512MB max
print(f"\nOptimal Config: {optimal}")Simulation Mining Crypto-monnaie
// scrypt pour Crypto-monnaies - Mining Configuration
// Inspiré de Litecoin et autres altcoins scrypt-based
class CryptocurrencyScryptMiner {
constructor(options = {}) {
// Configuration Litecoin-style (historique)
this.litecoinConfig = {
N: 1024, // 2^10 (LTC original)
r: 1, // Block size factor réduit
p: 1, // Pas de parallélisme
keylen: 32, // 256-bit output
target: 'Fast mining avec résistance ASIC'
};
// Configuration moderne haute sécurité
this.modernConfig = {
N: 32768, // 2^15
r: 8, // Standard
p: 1,
keylen: 32,
target: 'Maximum ASIC resistance'
};
this.config = options.mode === 'litecoin' ? this.litecoinConfig : this.modernConfig;
this.difficulty = options.difficulty || 1;
}
// Hash de bloc crypto-monnaie
async hashBlock(blockHeader, nonce = 0) {
const input = blockHeader + nonce.toString(16).padStart(8, '0');
return new Promise((resolve, reject) => {
const startTime = Date.now();
crypto.scrypt(input, 'salt', 32, {
N: this.config.N,
r: this.config.r,
p: this.config.p
}, (err, derivedKey) => {
if (err) {
reject(new Error(`Mining hash failed: ${err.message}`));
return;
}
const hashTime = Date.now() - startTime;
const hashHex = derivedKey.toString('hex');
resolve({
hash: hashHex,
nonce: nonce,
input: input,
difficulty_met: this.checkDifficulty(hashHex),
hash_time_ms: hashTime,
hashrate_estimate: `${(1000/hashTime).toFixed(2)} H/s`,
memory_usage_mb: Math.round((128 * this.config.N * this.config.r) / (1024 * 1024)),
algorithm: 'scrypt'
});
});
});
}
// Simulation mining avec proof-of-work
async mineBlock(blockHeader, maxAttempts = 1000000) {
console.log(`Starting mining with config: N=${this.config.N}, r=${this.config.r}`);
console.log(`Target difficulty: ${this.difficulty} leading zeros`);
const startTime = Date.now();
let attempts = 0;
for (let nonce = 0; nonce < maxAttempts; nonce++) {
attempts++;
try {
const result = await this.hashBlock(blockHeader, nonce);
if (result.difficulty_met) {
const totalTime = Date.now() - startTime;
return {
success: true,
block_hash: result.hash,
winning_nonce: nonce,
attempts: attempts,
total_time_ms: totalTime,
average_hashrate: `${(attempts / (totalTime / 1000)).toFixed(2)} H/s`,
memory_requirement: result.memory_usage_mb + ' MB',
asic_resistance: this.getAsicResistanceScore(),
proof_of_work: {
algorithm: 'scrypt',
config: this.config,
difficulty: this.difficulty,
verified: true
}
};
}
// Progress reporting pour long mining
if (attempts % 10000 === 0) {
const currentTime = Date.now();
const elapsed = (currentTime - startTime) / 1000;
const hashrate = attempts / elapsed;
console.log(`Progress: ${attempts} attempts, ${hashrate.toFixed(0)} H/s`);
}
} catch (error) {
console.error(`Mining error at nonce ${nonce}: ${error.message}`);
continue;
}
}
// Échec mining dans la limite d'attempts
return {
success: false,
attempts: attempts,
total_time_ms: Date.now() - startTime,
message: 'Max attempts reached without finding valid block',
suggestion: 'Reduce difficulty or increase maxAttempts'
};
}
// Vérification difficulté (leading zeros)
checkDifficulty(hash) {
const requiredZeros = '0'.repeat(this.difficulty);
return hash.startsWith(requiredZeros);
}
// Score résistance ASIC
getAsicResistanceScore() {
const memoryMB = (128 * this.config.N * this.config.r) / (1024 * 1024);
if (memoryMB >= 256) return 'EXCELLENT - ASIC mining uneconomical';
if (memoryMB >= 128) return 'GOOD - ASIC resistance high';
if (memoryMB >= 32) return 'MODERATE - Some ASIC resistance';
return 'LOW - ASICs may be viable';
}
// Analyse économique mining
calculateMiningEconomics(electricityCost_kWh = 0.10, hashrate_Hs = 1000, power_watts = 150) {
const memoryMB = (128 * this.config.N * this.config.r) / (1024 * 1024);
const timePerHash_s = 1 / hashrate_Hs;
// Coût électrique par hash
const powerCost_per_hour = (power_watts / 1000) * electricityCost_kWh;
const powerCost_per_hash = (powerCost_per_hour / 3600) * timePerHash_s;
return {
memory_requirement_mb: memoryMB,
time_per_hash_ms: timePerHash_s * 1000,
power_cost_per_hash: powerCost_per_hash.toFixed(8) + ' $',
daily_power_cost: (powerCost_per_hour * 24).toFixed(2) + ' $',
asic_viability: memoryMB > 128 ? 'Uneconomical' : 'Possibly viable',
gpu_efficiency: memoryMB < 512 ? 'Good' : 'Memory bound',
recommendation: this.getMiningRecommendation(memoryMB, timePerHash_s)
};
}
getMiningRecommendation(memoryMB, timePerHash) {
if (memoryMB > 512) {
return 'High memory config - Excellent ASIC resistance, suitable for fair mining';
} else if (memoryMB > 128) {
return 'Moderate memory - Good balance ASIC resistance and GPU efficiency';
} else {
return 'Low memory - Fast but lower ASIC resistance (legacy compatibility)';
}
}
}
// Usage Crypto Mining Simulation
const miner = new CryptocurrencyScryptMiner({
mode: 'modern', // or 'litecoin' for LTC-style
difficulty: 4 // 4 leading zeros
});
// Simulation mining d'un bloc
(async () => {
const blockHeader = 'Block#12345_timestamp_' + Date.now();
console.log('Starting cryptocurrency mining simulation...');
const result = await miner.mineBlock(blockHeader, 100000);
console.log('Mining Result:', result);
if (result.success) {
// Analyse économique
const economics = miner.calculateMiningEconomics(0.10, 500, 200);
console.log('Mining Economics:', economics);
}
})();Métriques Memory-Hard
vs Autres Algorithmes
scrypt a démontré sa résistance ASIC avec 13 années de protection effective des réseaux crypto-monnaies.
Ressources et Documentation
scrypt : Pionnier Memory-Hard et Résistance ASIC
scrypt a révolutionné la cryptographie en introduisant le concept memory-hard en 2009. Résistance ASIC démontrée par 13 années de protection des crypto-monnaies, standard IETF RFC 7914, et adoption continue pour applications nécessitant résistance maximale aux attaques matérielles spécialisées.